Re: why won't slicing lists raise IndexError?

2017-12-08 Thread breamoreboy
On Monday, December 4, 2017 at 7:10:01 PM UTC, Jason Maldonis wrote:
> I was extending a `list` and am wondering why slicing lists will never
> raise an IndexError, even if the `slice.stop` value if greater than the
> list length.
>
> Quick example:
>
> my_list = [1, 2, 3]
> my_list[:100]  # does not raise an IndexError, but instead returns the full
> list
>
> Is there any background on why that doesn't raise an IndexError? Knowing
> that might help me design my extended list class better. For my specific
> use case, it would simplify my code (and prevent `if isinstance(item,
> slice)` checks) if the slicing raised an IndexError in the example I gave.

This is explained in the Python tutorial for strings
https://docs.python.org/3/tutorial/introduction.html#strings, as a list is a
sequence just like a string it will act in exactly the same way.

--
Kindest regards.

Mark Lawrence.

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-08 Thread Rick Johnson
Steve D'Aprano wrote:

[...]

> You've already been told that there's no indication or
> reason to believe that it is a non-action. You've already
> been given at least one possible action. It isn't a non-
> action, it is two distinct actions:
>
> - the action you take when the slice is non-empty;
>
> - the action you take when the slice is empty.

When Python follows a logic clause like a train skating along a set of railroad
 tracks, and finds itself in a *GHOST TOWN*, that's not an action -- "Steve-o"
-- it's a non-
action.

Listen, I think it might help you to understand the absurdity of this
else-clause if you ruminate about this code using a metaphor. Below, i've
defined some fictional characters and objects that will live in a little
metaphorical world, and futhermore, explained how these characters and objects
relate to our real-life code example.



TERRY("THE BUILDER"): Terry is a personable fella who builds
little shanty towns for a living.

IF_VILLE: This is the first of two towns that Terry
establish in our little metaphorical world. And although
it's not quite the shining-city-on-a-hill that he, or the
inhabitants, had envisioned, he did manage to build a proper
train platform and a small warehouse for strong
deliverables, so we shouldn't be too critical of his work
here.

ELSE_VILLE: This is the "other" town that Terry establish.
However, after slaving away in the hot desert sun building
IF_VILLE all day, Terry decided to go home and drink a case
of beer, became drunk, and then forgot all about his
responsibilities to develope ELSE_VILLE. This has happened
before. But we typically forgive Terry for his irresponsible
nature simple because he's such a personable fella. However,
if this gets any worse, we may have to give him an
intervention.

KENNY_LINTER: Kenny Linter is a faithful civil servant who's
sole job is to inspect little shanty towns. And though he's
a little short on manners, he is typically competent
_enough_ to tell us if our towns are built to quality
standards, and if they're not built to quality standards,
well, it's his job to annoy us until we repair them.
Unfortunately, i've got some bad news to share with you.
After hastily exiting the train in ELSE-VILLE last night and
not realizing there was no platform in this town (Thanks
Terry!), KENNY_LINTER has broken both of his legs, fractured
an arm, and scratched his face up pretty bad. So i doubt
we'll be hearing from him in this episode, but stay tuned
for future appearances.

THE_TRAIN: The Train represents our Python script.

THE_TRACKS: The (railroad)tracks represent our program
logic. And the train's course is bound to these tracks

THE_ENGINEER: This is the Python runtime which "drives" the
train.

THE_TRACK_SWITCH: The Track Switch is a mechanical section
of the track (aka: logic gate) placed approximately halfway
between the train station and the two shanty towns that
Terry built. The switch allows the train to travel in one of
two directions -- one leading to IF_VILLE, and one leading
to ELSE_VILLE. Now, the mechanical apparatus of the switch
is spring loaded, and thus, by default, it always sends a
passing train to ELSE_VILLE. However, there is a tiny
control button mounted on a nearby fence post, one which
when pressed, will align the tracks with IF_VILLE. However,
since the trains in this metaphor have no brakes, and since
the button is really ~really~ small -- and since i couldn't
think of a more creative scenario! -- there is only one
creature who can press this button (TRUTHY_CLAWS!). And she
presses this button using one of her long pointy claws, and
thus, can send the train towards IF_VILLE.

TRUTHY_CLAWS: TruthyClaws (or "TC", as we like to call her)
is a mostly harmless anthropomorphized version of a
marsupial who's long claws only seem useful (at least upon
first sight) for causing a dreadful fright. But in reality,
these claws serve a vital purpose in our little metaphorical
world. You see, of ~all~ the characters in our little
universe, only TC (using one of her dreadfully long claws)
can press the little button on the TRACK_SWITCH and send us
along a path to IF-VILLE. And, every time TC takes a ride
with us in the train, she presses the little button for us,
and off we go to IF-VILLE (Hooray!). However, sometimes us
guys get a little rowdy and tell dirty jokes during the
trip, and TC, being uptight and all, tends to get offended,
and sometimes she refuses to ride with us. So, whenever TC
is with us, we always go to IF-VILLE, but if she's off
pouting somewhere, the train goes to ELSE-VILLE

THE_TRACK_DEVIL: The Track Devil is a supernatural being in
the mold of Loki who specializes in all forms of mischievous
pranks. And you 

why won't slicing lists raise IndexError?

2017-12-08 Thread Jason Maldonis
I was extending a `list` and am wondering why slicing lists will never raise an
 IndexError, even if the `slice.stop` value if greater than the list length.

Quick example:

my_list = [1, 2, 3]
my_list[:100]  # does not raise an IndexError, but instead returns the full
list

Is there any background on why that doesn't raise an IndexError? Knowing that
might help me design my extended list class better. For my specific use case,
it would simplify my code (and prevent `if isinstance(item, slice)` checks) if
the slicing raised an IndexError in the example I gave.

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-08 Thread Random832
On Mon, Dec 4, 2017, at 13:54, Jason Maldonis wrote:
> Is there any background on why that doesn't raise an IndexError? Knowing
> that might help me design my extended list class better. For my specific
> use case, it would simplify my code (and prevent `if isinstance(item,
> slice)` checks) if the slicing raised an IndexError in the example I
> gave.

Slicing (of strings, lists, tuples, anyway) never raises an IndexError. If the
start is out of range it will return an empty list. I don't know. As for "why",
 it's just how the operation was designed. Perhaps it was considered that an
exception isn't needed because there's no ambiguity (i.e. there's no other
reason a slice operation can return a list shorter than the length implied by
the slice parameters).

Why would this simplify your code? What are you doing that would benefit from
an IndexError here?

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-08 Thread Python
On Fri, Dec 08, 2017 at 05:12:35AM -0800, Rick Johnson wrote:
> I have already backed my argument with multiple code
> examples, exhaustive explanations

Which were all false and/or nonsensical.

> > if item:
> > process(item)
> > else:
> > do_without_item()
> 
> The above code sample is semantically equivalent to the
> following real-life "situational logic":
> 
> [man sits on couch and enjoys sports programming]
> 
> if thirsty:
> grab_beer_from_fridge()
> else:
> stay_on_couch()

So what you're ultimately saying is you're making an *assumption* that
the English phrase "do without item" MEANS to do nothing, and
therefore do_without_item() MUST be defined as pass.  However both of
those things are FALSE, and once again your entire argument is
completely invalid.  It's also true that such an assumption is
antithetical to the example.  So, your assumption is both logically
and contextually nonsensical.

If you're on a sinking boat, and you could stop the boat from sinking
if you had a rubber seal, but you don't have one, you're forced to
do_without_item().  Does that mean you're going to sit in the boat and
let it sink with you in it?  By your arguments, apparently YOU must...
But the rest of us would try to fix the leak another way, or failing
that, get the hell out of the boat.  I like our definition of
do_without_item() better.

Ned is right, you just need to be ingored.

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-08 Thread Rick Johnson
Python wrote:

[...]
>
> In this snippet (which again, we agreed was an incomplete
> academic example):
>
> if item:
> process(item)
> else:
> do_without_item()
>
> Can you please explain to me what sort of Python
> syntactical construct do_without_item() could be, other
> than a call to a Python callable object (i.e. a function)?
> Then, could you explain to me how that particular
> syntactical construct is in any way equivalent to the pass
> statement?  Could you then explain to me how using that in
> the simple example given makes any sense whatsoever?

I have already backed my argument with multiple code
examples, exhaustive explanations, and even constructed a
metaphor that was slightly entertaining. Yet, none of those
are good enough? Alas, allow me to try once more.

Consider:

> if item:
> process(item)
> else:
> do_without_item()

The above code sample is semantically equivalent to the
following real-life "situational logic":

[man sits on couch and enjoys sports programming]

if thirsty:
grab_beer_from_fridge()
else:
stay_on_couch()

Above, just as with Terry's code, the else-clause cannot
justify itself. And why you ask? Because, we were _already_
on the damned couch! The else-clause is a "do nothing"
condition, hence, it is functionally equivalent to:

else:
pass

*HENCE*, it is super-freaking-fluous! Get it?

However. Here is an example which _can_ justify the else-
clause

if thirsty and (not tooLazyToMove):
grab_beer_from_fridge()
else:
tell_wife_to_grab_beer()

Heck, even tangential actions can be justified. Observe:

import random

if thirsty and (not tooLazyToMove):
grab_beer_from_fridge()
else:
random.choice([
scratch_self,
eat_tater_chip,
change_channel,
relieve_abdominal_pressure,
])()
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-08 Thread Ned Batchelder

On 12/7/17 9:02 PM, Python wrote:

Can you please explain to me 


Really, you just have to ignore him.

--Ned.

--
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-07 Thread Python
Hi Rick!

On Wed, Dec 06, 2017 at 04:05:42PM -0800, Rick Johnson wrote:
> Python wrote:
> 
> [...]
> 
> > THIS IS FALSE.  CALLING A FUNCTION
> 
> What *FUNCTION*?

In this snippet (which again, we agreed was an incomplete academic
example):

if item:
process(item)
else:
do_without_item()

Can you please explain to me what sort of Python syntactical construct
do_without_item() could be, other than a call to a Python callable
object (i.e. a function)?  Then, could you explain to me how that
particular syntactical construct is in any way equivalent to the pass
statement?  Could you then explain to me how using that in the simple
example given makes any sense whatsoever?

[FWIW, if there is an answer to this, I am genuinely interested...]

Since it can indeed be a function call, then if you can't do all of
the above things, doesn't that imply that in the example given,
do_witout_item() can't be anything BUT a function call?  Even if it
somehow doesn't by some logic that escapes me, for the purposes of
this simple academic example, isn't it preferable to assume that it is
the most obvious thing (i.e. a function call)?

Isn't the else clause in fact NOT superfluous, because it illustrates
that if the slice operation would be out of the container object's
bounds, then item will be assigned a value that evaluates to false,
enabling one to trigger the else clause of an if block to do something
ONLY under that condition?

> if "do_without_item()" had been defined, then you could call
> it a function. But until you do, it's just a NameError.

OK!  Then could you explain to me how a NameError is equivalent to the
pass statement?  I thought one continued execution without any side
effects, and the other required handling or else will stop the
program.  Isn't that in fact functionally nonequivalent?

Thanks.

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-06 Thread Rick Johnson
Alexandre Brault wrote:

[...]

> process() wasn't defined either, nor were n and seq and yet
> you're not complaining about them.

Why would i? Both are highly relevant to the example of
performing a slice. "Don't throw the baby out with the
bathwater", as they say...

> It seems it was clear to everyone but you that seq was a
> sequence defined elsewhere, n was an index defined
> elsewhere, and both process and do_without_item were
> functions defined elsewhere.

OMG! I never would have guessed that! O_O

And whilst we can see that your cryptology skills are quite
impressive -- and by impressive, i mean, like up there with
some of the best cryptologist in the world, impressive --
your ability to distinguish between the portions of this
teeny tiny example that are _relevant_ to the action of
performing a slice, and the portions that are _irrelevant_
to performing a slice, leads me to the conclusion that your
ability to make simple value judgments is seriously
flawed, or missing altogether.

If we consider the entire working sample that Ned offered
(because Ned is the only person from your side who's
bothered to offer error-free code) and we break this code
down into its relevant parts, starting from the most
relevant part (the actual slice), and extending the scope
outwards from there, each time enveloping only the minimum
structures required to maintain legal code, we will see that
all of the structures *SANS* the else-clause can be
justified. The function can be justified because it wraps
the contents in a self contained reusable code object.
Likewise, the conditional *if-clause* can be justified
because it brings logic into the equation. But the else-
clause is only relevant to the if-clause, and does not offer
_enough_ useful content of its own to validate its own
existence.

> And even if you want to be so incredibly pedantic that
> do_without_item (and only do_without_item, because the rest
> of the code fragment seems to get your seal of approval) is
> not defined, your "functioning equivalent" is still not
> equivalent, because the original code would have raised a
> NameError that yours doesn't.

Oh this is rich. Now i'm wrong because my code executes
_cleanly_? You must be joking!
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-06 Thread Ned Batchelder
After a certain point, the only thing you can do with a troll is ignore 
them.


--Ned.
--
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-06 Thread Alexandre Brault
process() wasn't defined either, nor were n and seq and yet you're not 
complaining about them.


It seems it was clear to everyone but you that seq was a sequence 
defined elsewhere, n was an index defined elsewhere, and both process 
and do_without_item were functions defined elsewhere.


And even if you want to be so incredibly pedantic that do_without_item 
(and only do_without_item, because the rest of the code fragment seems 
to get your seal of approval) is not defined, your "functioning 
equivalent" is still not equivalent, because the original code would 
have raised a NameError that yours doesn't.



On 2017-12-06 7:05 PM, Rick Johnson wrote:

Python wrote:

[...]


THIS IS FALSE.  CALLING A FUNCTION

What *FUNCTION*?

You think you can just slap a function-y looking symbol
willy-nilly in the middle of a chunk of code and then have
it "magically" transform into a python function object?

 >>> do_without_item()

 Traceback (most recent call last):
   File "", line 1, in 
 do_without_item()
 NameError: name 'do_without_item' is not defined
 >>> foo()

 Traceback (most recent call last):
   File "", line 1, in 
 foo()
 NameError: name 'foo' is not defined
 >>> bar()

 Traceback (most recent call last):
   File "", line 1, in 
 bar()
 NameError: name 'bar' is not defined

if "do_without_item()" had been defined, then you could call
it a function. But until you do, it's just a NameError.


--
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-06 Thread Rick Johnson
Python wrote:

[...]

> THIS IS FALSE.  CALLING A FUNCTION

What *FUNCTION*?

You think you can just slap a function-y looking symbol
willy-nilly in the middle of a chunk of code and then have
it "magically" transform into a python function object?

>>> do_without_item()

Traceback (most recent call last):
  File "", line 1, in 
do_without_item()
NameError: name 'do_without_item' is not defined
>>> foo()

Traceback (most recent call last):
  File "", line 1, in 
foo()
NameError: name 'foo' is not defined
>>> bar()

Traceback (most recent call last):
  File "", line 1, in 
bar()
NameError: name 'bar' is not defined

if "do_without_item()" had been defined, then you could call
it a function. But until you do, it's just a NameError.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-06 Thread Rick Johnson
Terry Reedy wrote:

[...]

> Rick, cut the crap.  If you do not understand that
> 'something_else()' != 'pass', re-read the tutorial.

How is the official tutorial going to give me any insight
into an undefined symbol that you invented?

Of course, we all understand that "something_else()" is
merely a semantical placeholder which is synonomous with
"fill_in_the_blank()" or "do_as_you_please()".

I'm sure the OP is competent enough to decide when his/her
if-clauses need to grow a complementary else-clause, or when
a chain of elif-clauses are required as well. My intention
was not to make you out as some sort of boogeyman, i simply
want to inform those watching. So no need to take any of
this personally.

> The OP asked: "Why is slicing 'forgiving'?"  The current
> behavior could be interpreted as 'letting errors pass
> silently'. It would be if slicing meant 'give me exactly
> the length stop-start subsequence from start to stop (or
> raise)'.  But slicing actually means 'give me whatever
> subsequence exists between start and stop'.

Agreed.

> My examples attempted to show why this looser definition of
> slicing is *useful*.  The focus of the third example was
> entirely on the condition, not the alternative actions.
> (Reminder: either action can be the if-action, and the
> other the else-action, depending on how the condition is
> written.)

True. But your conditional presented a specific binary
choice, where the if-clause takes the role of a
"TRUTHY_CLAWS", and the else-clause takes the role of a
"FALSEY_CLAWS".

Unfortunately i didn't get a chance to work FLASEY_CLAWS
into my metaphor, hmm, as i was afraid the power dynamic
between the two "clawed marsupials" might distract from the
narrative. TC always has to be first in everything. That's
the way she is, i'm afraid.


> I should have mentioned, and others did, that the OP can
> write a custom __getitem__ method that implements stricter
> slicing for instances of a custom class.

Yep. Could name it "StrictSlice".

> I think we have collectively answered the OP's question
> quite well.

Yes. 

But i like to take advantage of any tangential teaching
moments whenever they arise. And don't forget, the OP is not
the only person who is learning from this exchange. We are
all students of knowledge.

--

https://plus.google.com/u/0/collection/UAv9UE
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-06 Thread Python
On Wed, Dec 06, 2017 at 03:08:51PM -0800, Rick Johnson wrote:
> The following is Terry's original:
> 
> if item:
> process(item)
> else:
> do_without_item()
> 
> And here is the functioning equivalent, sans any fuzzy
> semantics:
> 
> if item:
> process(item)
> else:
> pass
> 

THIS IS FALSE.  CALLING A FUNCTION IS NOT FUNCTIONALLY EQUIVALENT TO
THE PASS STATEMENT.  Therefore your entire premise is false, and the
remainder of what you said is meaningless.

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-06 Thread Rick Johnson
On Wednesday, December 6, 2017 at 3:13:41 PM UTC-6, Python wrote:
[...]
> Geez, seriously?  The snippet is purely academic, obviously
> not a complete or useful program,

Who ever made the claim that it was?

> intended to illustrate that python can take two different
> branches depending on whether or not the slicing operation
> yeilded a non-empty container, using uncomplicated syntax.
> It effectively serves that purpose.

"Uncomplicated" is a relative term, not an absolute.

The following is Terry's original:

if item:
process(item)
else:
do_without_item()

And here is the functioning equivalent, sans any fuzzy
semantics:

if item:
process(item)
else:
pass

And finally, here is the functioning equivalent, sans the
fuzzy semantics *AND* the forced vist to a little "ghost
town".

if item:
process(item)

My point is simple: What good could possibly come from
posting bloat-ware example code? The else-clause is
superfluous. How many times must i explain this simple
concept before you will admit you are wrong?

> Moreover, in order for the example to make sense, we must
> assume the existence of unspecified code: The variables
> need to have been initialized previously, or else the
> snippet is non-functional.

Agreed.

> The if conditional would never be reached.  We can as
> easily assume that the hypothetical example continues with
> other, unspecified code, and that the equally unspecified
> do_without_item() actually does something,

Fine. Why stop at a single if/else binary? Why not offer
N more irrelevant clauses?

import os, re
value = "foo"
if value:
do_something1(value)
elif isinstance(value, (int, float)):
do_something_else1(value)
elif os.path.exists(value):
do_something_else2(value)
elif re.match(r'.*ly', value):
do_something_else3(value)
else:
do_nothing()

The possibilities are literally endless.

> which renders your argument completely invalid and
> pointless.

And that's an opinion you get to have.

> The whole thing is entirely academic; continuing to argue
> this is an utter waste of time and bandwidth.

Yet, here you are, apeaking on behalf of others. It boggles
the mind.

--

https://plus.google.com/u/0/collection/UAv9UE

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-06 Thread Terry Reedy

On 12/5/2017 9:23 PM, Rick Johnson wrote:

Steve D'Aprano wrote:

[...]


You've already been told that there's no indication or
reason to believe that it is a non-action. You've already
been given at least one possible action. It isn't a non-
action, it is two distinct actions:

- the action you take when the slice is non-empty;

- the action you take when the slice is empty.


When Python follows a logic clause like a train skating
along a set of railroad tracks, and finds itself in a *GHOST
TOWN*, that's not an action -- "Steve-o" -- it's a non-
action.


Rick, cut the crap.  If you do not understand that 'something_else()' != 
'pass', re-read the tutorial.

---

The OP asked: "Why is slicing 'forgiving'?"  The current behavior could 
be interpreted as 'letting errors pass silently'.  It would be if 
slicing meant 'give me exactly the length stop-start subsequence from 
start to stop (or raise)'.  But slicing actually means 'give me whatever 
subsequence exists between start and stop'.


My examples attempted to show why this looser definition of slicing is 
*useful*.  The focus of the third example was entirely on the condition, 
not the alternative actions.  (Reminder: either action can be the 
if-action, and the other the else-action, depending on how the condition 
is written.)


I should have mentioned, and others did, that the OP can write a custom 
__getitem__ method that implements stricter slicing for instances of a 
custom class.


I think we have collectively answered the OP's question quite well.

--
Terry Jan Reedy

--
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-06 Thread Python
On Tue, Dec 05, 2017 at 06:23:04PM -0800, Rick Johnson wrote:
> [bunch of old, irrelevant context snipped]
> > item = seq[n:n+1]
> > if item:
> >  process(item)
> > else:
> >  do_without_item()
> 
> When Python follows a logic clause like a train skating
> along a set of railroad tracks, and finds itself in a *GHOST
> TOWN*, that's not an action -- "Steve-o" -- it's a non-
> action.

Geez, seriously?  The snippet is purely academic, obviously not a
complete or useful program, intended to illustrate that python can
take two different branches depending on whether or not the slicing
operation yeilded a non-empty container, using uncomplicated syntax.
It effectively serves that purpose.

Moreover, in order for the example to make sense, we must assume the
existence of unspecified code:  The variables need to have been
initialized previously, or else the snippet is non-functional.  The if
conditional would never be reached.  We can as easily assume that the
hypothetical example continues with other, unspecified code, and that
the equally unspecified do_without_item() actually does something,
which renders your argument completely invalid and pointless.

The whole thing is entirely academic; continuing to argue this is an
utter waste of time and bandwidth.

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-05 Thread Rick Johnson
Steve D'Aprano wrote:

[...]

> You've already been told that there's no indication or
> reason to believe that it is a non-action. You've already
> been given at least one possible action. It isn't a non-
> action, it is two distinct actions:
>
> - the action you take when the slice is non-empty;
>
> - the action you take when the slice is empty.

When Python follows a logic clause like a train skating
along a set of railroad tracks, and finds itself in a *GHOST
TOWN*, that's not an action -- "Steve-o" -- it's a non-
action.

Listen, I think it might help you to understand the
absurdity of this else-clause if you ruminate about this
code using a metaphor. Below, i've defined some fictional
characters and objects that will live in a little
metaphorical world, and futhermore, explained how these
characters and objects relate to our real-life code example.



TERRY("THE BUILDER"): Terry is a personable fella who builds
little shanty towns for a living.

IF_VILLE: This is the first of two towns that Terry
establish in our little metaphorical world. And although
it's not quite the shining-city-on-a-hill that he, or the
inhabitants, had envisioned, he did manage to build a proper
train platform and a small warehouse for strong
deliverables, so we shouldn't be too critical of his work
here.

ELSE_VILLE: This is the "other" town that Terry establish.
However, after slaving away in the hot desert sun building
IF_VILLE all day, Terry decided to go home and drink a case
of beer, became drunk, and then forgot all about his
responsibilities to develope ELSE_VILLE. This has happened
before. But we typically forgive Terry for his irresponsible
nature simple because he's such a personable fella. However,
if this gets any worse, we may have to give him an
intervention.

KENNY_LINTER: Kenny Linter is a faithful civil servant who's
sole job is to inspect little shanty towns. And though he's
a little short on manners, he is typically competent
_enough_ to tell us if our towns are built to quality
standards, and if they're not built to quality standards,
well, it's his job to annoy us until we repair them.
Unfortunately, i've got some bad news to share with you.
After hastily exiting the train in ELSE-VILLE last night and
not realizing there was no platform in this town (Thanks
Terry!), KENNY_LINTER has broken both of his legs, fractured
an arm, and scratched his face up pretty bad. So i doubt
we'll be hearing from him in this episode, but stay tuned
for future appearances.

THE_TRAIN: The Train represents our Python script.

THE_TRACKS: The (railroad)tracks represent our program
logic. And the train's course is bound to these tracks

THE_ENGINEER: This is the Python runtime which "drives" the
train.

THE_TRACK_SWITCH: The Track Switch is a mechanical section
of the track (aka: logic gate) placed approximately halfway
between the train station and the two shanty towns that
Terry built. The switch allows the train to travel in one of
two directions -- one leading to IF_VILLE, and one leading
to ELSE_VILLE. Now, the mechanical apparatus of the switch
is spring loaded, and thus, by default, it always sends a
passing train to ELSE_VILLE. However, there is a tiny
control button mounted on a nearby fence post, one which
when pressed, will align the tracks with IF_VILLE. However,
since the trains in this metaphor have no brakes, and since
the button is really ~really~ small -- and since i couldn't
think of a more creative scenario! -- there is only one
creature who can press this button (TRUTHY_CLAWS!). And she
presses this button using one of her long pointy claws, and
thus, can send the train towards IF_VILLE.

TRUTHY_CLAWS: TruthyClaws (or "TC", as we like to call her)
is a mostly harmless anthropomorphized version of a
marsupial who's long claws only seem useful (at least upon
first sight) for causing a dreadful fright. But in reality,
these claws serve a vital purpose in our little metaphorical
world. You see, of ~all~ the characters in our little
universe, only TC (using one of her dreadfully long claws)
can press the little button on the TRACK_SWITCH and send us
along a path to IF-VILLE. And, every time TC takes a ride
with us in the train, she presses the little button for us,
and off we go to IF-VILLE (Hooray!). However, sometimes us
guys get a little rowdy and tell dirty jokes during the
trip, and TC, being uptight and all, tends to get offended,
and sometimes she refuses to ride with us. So, whenever TC
is with us, we always go to IF-VILLE, but if she's off
pouting somewhere, the train goes to ELSE-VILLE

THE_TRACK_DEVIL: The Track Devil is a supernatural being in
the mold of Loki who specializes in all forms of mischievous
pranks. And you 

Re: why won't slicing lists raise IndexError?

2017-12-05 Thread Steve D'Aprano
On Tue, 5 Dec 2017 11:31 pm, Rick Johnson wrote:

> Ned Batchelder wrote:
> [...]
>> Your original statement sounded like, "The else clause can
>> never be executed,"
> 
> No. Of course not. Note that i mentioned _pragmatism_. My
> complaint about the else-clause was not that it could
> _never_ be executed, my complaint that was that the else-
> clause (in Terry's example) serves no useful purpose save to
> act as a semantical placeholder for a non-action.

When you find yourself in a hole, stop digging.

You've already been told that there's no indication or reason to believe that
it is a non-action. You've already been given at least one possible action.
It isn't a non-action, it is two distinct actions:

- the action you take when the slice is non-empty;

- the action you take when the slice is empty.



> Heck, it 
> doesn't even log anything! "Practicality beats purity". For
> instance:
> 
> (1) Would it be practical to make a shopping list that
> includes only the products you _don't_ want to buy?

Obviously not *only* the products you don't want, but it is very common to
specify constraints, e.g. what you don't want.

New car. Must not have an internet connected engine.

Gluten-free bread.

Unscented toilet paper.

Ingredients to make fruit salad. No bananas.

Or alternatives:

Get a slice of pizza for lunch. If they're out of pizza (i.e. the
slice is empty) get Chinese food instead.


> (2) How about a list of navigation directions that includes
> tangential info?
>   
> "After you take the second left turn, you'll see a big
> windmill -- just ignore that"

Be careful about rhetorical questions. The answer is not always what you think
it must be.

Giving directions that include landmarks is *very* useful. If you don't see
the windmill, you know you've taken the wrong turn. When you do see it, you
know you're on the right track.


> (3) How about a recipe that includes non-ingredients?

My wife is an expert at making bread-and-no-butter pudding. This should be
obvious, but in case it isn't, the reason it has that name is because it is a
modified recipe based on (can you guess what?) bread-and-butter pudding, a
British staple.

Also:

Flourless orange cake.

Taken from a recipe for cooking lentils:

"Don't add vinegar, as it makes the lentils tough."

(Apparently some people add vinegar when cooking pulses. Curious.)

And for those who are well-educated but not wise:

"The difference between being educated and being smart is, the 
educated person knows that tomato is a fruit, while the wise
person knows not to put tomato in fruit salad."

I can think of a couple of people I would need to write "No tomatoes" on any
fruit salad recipe I gave them.



>> which would have been in direct opposition to the point,
>> that slicing outside the limits would produce an empty
>> list, not an exception.
> 
> And again, that is precisely why i raised an objection to
> this else-clause. Because the inclusion of this else-clause
> is a distraction from the point.

Ah, we've entered Ricksville, where demonstrating that slicing can return an
empty list is taken as distraction from the point that slicing can return an
empty list.

No, wait, you've convinced me Rick! Your logic is impeccable! Except for one
teeny tiny flaw in your reasoning -- you have the conclusion backwards. Its
not the *empty* slice (the else clause) that is the distraction. Its the
*non* empty clause. We already know that slicing returns a list of items. The
part we're discussing is what happens when the slice is out of bounds? Does
it return an empty list, or raise an exception?


alist = bigger_list[start:finish]
if not alist:
print("Look Ma, no exception was raised!!!")


/only half serious


[...]
> item = seq[n:n+1]
> if item:
> process(item)
> else:
> do_without_item()
>  
> "do_without_item()" implies a non-action.

The mind boggles how you get by in real life, when you're so busy digging
yourself into deeper and deeper holes. Do you think about things before you
write them?

"I was going to make spaghetti and meat balls for tea tonight, but the store
was out of mince, so I'll have to do without meat balls."

Does that mean I go hungry and don't eat?


>> Perhaps I have a simulation on a conceptually infinite
>> line, but only store the actual points needed.  The "non
>> action" would be to extend the line.
> 
> That logic does not follow! How do you _extend_ an infinite
> line? :-). 

Ned said that the line stores only the points needed. If you've only used
positions between 1 and 10, only values 1 through 10 have been stored. If you
then try to access position 20, the line is extended to position 20.


> Of course, in the realm of maths, a line is by 
> definition infinite.

Not necessarily. Lines can be finite (e.g. a chord) or infinite, and if
infinite, they can be defined as extending towards infinity in both

Re: why won't slicing lists raise IndexError?

2017-12-05 Thread Rick Johnson
Ned Batchelder wrote:
[...]
> Your original statement sounded like, "The else clause can
> never be executed," 

No. Of course not. Note that i mentioned _pragmatism_. My
complaint about the else-clause was not that it could
_never_ be executed, my complaint that was that the else-
clause (in Terry's example) serves no useful purpose save to
act as a semantical placeholder for a non-action. Heck, it
doesn't even log anything! "Practicality beats purity". For
instance:

(1) Would it be practical to make a shopping list that
includes only the products you _don't_ want to buy?

no ham
no eggs
no spam
no Limburger

"Okay, but what do we _need_!!!"

(2) How about a list of navigation directions that includes
tangential info?

"After you take the second left turn, you'll see a big
windmill -- just ignore that"

(3) How about a recipe that includes non-ingredients?

1 egg
2 pounds of ham
0 teaspoons coarse sea-salt
0 cups of finely shreded Limburger
...

> which would have been in direct opposition to the point,
> that slicing outside the limits would produce an empty
> list, not an exception.

And again, that is precisely why i raised an objection to
this else-clause. Because the inclusion of this else-clause
is a distraction from the point.

> I'm not sure why you are certain that there's never a
> reason to execute code in that case.

Oh, there will be a _reason_ for else-clause to execute
(when the slice overlaps the boundary), but i argue the code
contained within is not a _good_ reason for it to execute.

item = seq[n:n+1]
if item:
process(item)
else:
do_without_item()
 
"do_without_item()" implies a non-action. However, that's
not to say that under different circumstances, the else-
clause might serve a practical purpose for a programmer. For
instance, even a logging event serves a purpose.

ss, se = n, n+1
item = seq[ss:se]
if item:
process(item)
else:
print('Slice ({0}, {1}) out of bounds!'.format(ss, se))

> Perhaps I have a simulation on a conceptually infinite
> line, but only store the actual points needed.  The "non
> action" would be to extend the line.

That logic does not follow! How do you _extend_ an infinite
line? :-). Of course, in the realm of maths, a line is by
definition infinite.

But whether you're speaking in metaphor or not, there are
literally infinite ways in which an else-clause can be
justified. My argument was simply: "do_without_item()" is
not a legitimate justification.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-05 Thread Ned Batchelder

On 12/4/17 10:41 PM, Rick Johnson wrote:

I think we've demonstrated the slicing semantics well.

Indeed. And i never questioned this aspect. I merely wanted
to inform the lurkers that the else-clause was handling a
non-action, and therefore, could be omitted.


Your original statement sounded like, "The else clause can never be 
executed," which would have been in direct opposition to the point, that 
slicing outside the limits would produce an empty list, not an 
exception.  I'm not sure why you are certain that there's never a reason 
to execute code in that case.


Perhaps I have a simulation on a conceptually infinite line, but only 
store the actual points needed.  The "non action" would be to extend the 
line.


--Ned.
--
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-04 Thread Rustom Mody
On Tuesday, December 5, 2017 at 12:40:01 AM UTC+5:30, Jason Maldonis wrote:
> I was extending a `list` and am wondering why slicing lists will never
> raise an IndexError, even if the `slice.stop` value if greater than the
> list length.
> 
> Quick example:
> 
> my_list = [1, 2, 3]
> my_list[:100]  # does not raise an IndexError, but instead returns the full
> list
> 
> Is there any background on why that doesn't raise an IndexError? Knowing
> that might help me design my extended list class better. For my specific
> use case, it would simplify my code (and prevent `if isinstance(item,
> slice)` checks) if the slicing raised an IndexError in the example I gave.


Data Structures have invariants.
Some of these are just side-notes… interesting, cute
Some are more fundamental, the raison d'être for the data structure

Whether the following inv is that fundamental or not I wont offer an opinion
It certainly seems important (to me)

Python slice inv:   (∀ n:ℤ, l:sequence | l[:n] + l[n:] == l)

Your preferred inv:   (∀ n:ℤ, l:sequence ∧ jason_caveat(n) | l[:n] + l[n:] == l)
  where
   def jason_caveat(n,l):
  return 0 ≤ n ≤ len(l)

Do you consider it arguable that your preferred invariant is at least
more heavy-weight if not downright clunkier?

Note I am not offering a view on this.

eg for zip python does this

>>> zip([1,2,3], [4,5,6,7,8])
[(1, 4), (2, 5), (3, 6)]

I find myself sometimes needing this

Sometimes needing it extended to the longer (with what??)

Sometimes needing your preferred behavior — an exception

On a more fundamental note:
def const(x): return 42

has the invariant that const(x) == 42 when x is well-defined
This is true for most mainstream languages

Lazy functional languages (like Haskell) make a big deal of not having the
definedness caveat.
People (like me) not quite on the FP bandwagon are conflicted on whether the
mathematical elegance is worth the computational mess
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-04 Thread Rick Johnson
Ned Batchelder wrote:
[...]
> The point of the example was to demonstrate what happens
> when slicing beyond the bounds of the list.  It's beyond
> the scope of the thread to debate whether you might want to
> perform an action in that case. 

But, nevertheless, the else-clause is there! And that's the
point i've been trying to make. The inclusion of this else-
clause only serves to distract from the intent of the lesson
and also the main topic of the thread. Hence my objection.

> I think we've demonstrated the slicing semantics well.

Indeed. And i never questioned this aspect. I merely wanted
to inform the lurkers that the else-clause was handling a
non-action, and therefore, could be omitted.

I believe strongly that bad examples are worse than no
examples at all. Consider the following:

Take for example the Tkinter method `root.quit()`, a method
that was presented in a famous web tutorial many years ago,
and has since (even to this _day_!) caused misconceptions in
the mind's of noobs as to its _true_ function. Sure, part of
that misconception can be blamed on a poor name choice, as
root.suspend_event_processing() would have been self-
explanatory. But this method is for advanced usage, and
thus, should not be a part of _any_ introductory or even
intermediate lesson. Of course, once the tut owner posted
this bad code, other tut owners just blindly copy/pasted,
and the damage has spread all over the web.

Or the example code presented as an introductory to defining
functions in the official Python documentation, one which
distracts from the main topic with an algorithm which builds
a Fibonacci sequence. 

Both of these examples underscore the importance of clear
presentation, and what can go wrong if one fails to heed
this protocol of good teaching.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-04 Thread Ned Batchelder

On 12/4/17 9:31 PM, Rick Johnson wrote:

On Monday, December 4, 2017 at 7:47:20 PM UTC-6, Ned Batchelder wrote:

[...]
 

Here are details filled in:

 $ python3.6
 Python 3.6.3 (default, Oct  4 2017, 06:03:25)
 [GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.37)] on darwin
 Type "help", "copyright", "credits" or "license" for more information.
  >>> def do_the_thing(seq, n):
 ... item = seq[n:n+1]
 ... if item:
 ... print(f"process({item})")
 ... else:
 ... print("do_without_item()")
 ...
  >>> do_the_thing([1, 2, 3], 2)
 process([3])
  >>> do_the_thing([1, 2, 3], 5)
 do_without_item()
  >>>

Thanks for filling in the blanks. However, my objection to
this else-clause stems from a perspective based in
pragmatics. Specifically, i see no benefit here in logging
the "non-action". Sure, perhaps logging a non-action may serve a
useful purpose during debugging sessions, but i find them to
be nothing but useless noise in production code.

Do you agree or disagree with my assessment?

If you disagree, please explain why.


The point of the example was to demonstrate what happens when slicing 
beyond the bounds of the list.  It's beyond the scope of the thread to 
debate whether you might want to perform an action in that case.  I 
think we've demonstrated the slicing semantics well.


--Ned.
--
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-04 Thread Chris Angelico
On Tue, Dec 5, 2017 at 1:31 PM, Rick Johnson
 wrote:
> On Monday, December 4, 2017 at 7:47:20 PM UTC-6, Ned Batchelder wrote:
>
> [...]
>
>> Here are details filled in:
>>
>> $ python3.6
>> Python 3.6.3 (default, Oct  4 2017, 06:03:25)
>> [GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.37)] on darwin
>> Type "help", "copyright", "credits" or "license" for more information.
>>  >>> def do_the_thing(seq, n):
>> ... item = seq[n:n+1]
>> ... if item:
>> ... print(f"process({item})")
>> ... else:
>> ... print("do_without_item()")
>> ...
>>  >>> do_the_thing([1, 2, 3], 2)
>> process([3])
>>  >>> do_the_thing([1, 2, 3], 5)
>> do_without_item()
>>  >>>
>
> Thanks for filling in the blanks. However, my objection to
> this else-clause stems from a perspective based in
> pragmatics. Specifically, i see no benefit here in logging
> the "non-action". Sure, perhaps logging a non-action may serve a
> useful purpose during debugging sessions, but i find them to
> be nothing but useless noise in production code.
>
> Do you agree or disagree with my assessment?
>
> If you disagree, please explain why.

Why do you believe this to be a non-action? There is no indication
that do_without_item does nothing.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-04 Thread Rick Johnson
On Monday, December 4, 2017 at 7:47:20 PM UTC-6, Ned Batchelder wrote:

[...]

> Here are details filled in:
> 
> $ python3.6
> Python 3.6.3 (default, Oct  4 2017, 06:03:25)
> [GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.37)] on darwin
> Type "help", "copyright", "credits" or "license" for more information.
>  >>> def do_the_thing(seq, n):
> ... item = seq[n:n+1]
> ... if item:
> ... print(f"process({item})")
> ... else:
> ... print("do_without_item()")
> ...
>  >>> do_the_thing([1, 2, 3], 2)
> process([3])
>  >>> do_the_thing([1, 2, 3], 5)
> do_without_item()
>  >>>

Thanks for filling in the blanks. However, my objection to
this else-clause stems from a perspective based in
pragmatics. Specifically, i see no benefit here in logging
the "non-action". Sure, perhaps logging a non-action may serve a
useful purpose during debugging sessions, but i find them to
be nothing but useless noise in production code.

Do you agree or disagree with my assessment?

If you disagree, please explain why.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-04 Thread MRAB

On 2017-12-05 01:37, Jason Maldonis wrote:
[snip]


So I guess the conclusion (as far as I can tell) is that:  `my_string[:n]`
is more convenient than `my_string[:min(n, len(my_string))]`, and that
sounds okay enough to me.

If I'm being completely honest I kinda like the logical explicitness of the
latter, but it's way less convenient. And I'm 100% sure the people who made
this decision are incredibly smart, and I certainly trust their decision.
Thanks everyone for the responses.

The first sentence of this paragraph can be summarised as "Practicality 
beats purity". It's in the Zen.

--
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-04 Thread Ned Batchelder

On 12/4/17 8:03 PM, Rick Johnson wrote:

On Monday, December 4, 2017 at 6:13:19 PM UTC-6, Chris Angelico wrote:

[...]
 

Ahhh, I see how it is. You didn't run the code, ergo you
don't understand it. Makes perfect sense. :)

Being that Terry didn't offer any declarations or defintions
for his variables or functions, i assumed, i suppose, like
any other rational person, that it was all just pseudo code.

But, in any event, i don't see how running the code and then
watching helplessly as a volley of NameErrors come rip-
roaring down a stdout stream like a half naked, middle-aged
drunk feller bobbing precariously along a river rapid --
hey, look out for that rock! -- is going to help shed any
light on any of this.

But i suppose it's possible i missed an esoteric joke
somewhere...


Here are details filled in:

   $ python3.6
   Python 3.6.3 (default, Oct  4 2017, 06:03:25)
   [GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.37)] on darwin
   Type "help", "copyright", "credits" or "license" for more information.
>>> def do_the_thing(seq, n):
   ... item = seq[n:n+1]
   ... if item:
   ... print(f"process({item})")
   ... else:
   ... print("do_without_item()")
   ...
>>> do_the_thing([1, 2, 3], 2)
   process([3])
>>> do_the_thing([1, 2, 3], 5)
   do_without_item()
>>>

--Ned.
--
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-04 Thread Jason Maldonis
I'll try to summarize what I've learned with a few responses in hodge-podge
order and to no one in particular:

>That's a feature dude, not a bug.

Absolutely. I _do not_ think that how slicing works in python should be
changed, but I _do_ want to understand its design decisions because it will
make me a better programmer.

>one thing Python consistently emphasises is making things easy for
>the user, even if that convenience comes at a cost to the implementer.

I completely agree, and I'm always happy to do the work as a developer to
make the user experience better. That's something I really appreciate about
python as well.

>I've got a buffer class with that behaviour which is very useful for
parsing data streams.
[...]
>In summary, I think you should give your LazyList a .extend method to
establish your code's precondition (enough elements) and then you can
proceed with your slicing in surety that it will behave correctly.

Thanks for this detailed response, I'll have to reread it a few times to
understand it but I think I'll understand how I might improve my
implementation from your example. In particular, that last "In summary"
sentence hit on something I'd been thinking about. A `.extend` method might
clean things up nicely.

--
It seems to me that the consensus on the reason for why slices don't throw
IndexErrors is essentially "It's very convenient for them not to" and I'm
just fine with that response (not super thrilled, but happy enough). There
were two comments in particular that sounded pretty good:

>But as a user, I can say that I find the ability to use slices without
checking for
>out of bounds cases or handling exceptions to be really convenient.

That's fair.  The alternative would be something that someone else
mentioned:  `my_string[ : min(n, len(my_string))]` and that's not very
pretty, although I don't think it's absolutely horrible.

And: the use case where you are trying to split a list or string at index
`n` is:  `first_half, second_half = my_string[:n], my_string[n:]`  and if n
> len(my_string) then this use case becomes a bit annoying to write
(although it could use the `min` example above).

So I guess the conclusion (as far as I can tell) is that:  `my_string[:n]`
is more convenient than `my_string[:min(n, len(my_string))]`, and that
sounds okay enough to me.

If I'm being completely honest I kinda like the logical explicitness of the
latter, but it's way less convenient. And I'm 100% sure the people who made
this decision are incredibly smart, and I certainly trust their decision.
Thanks everyone for the responses.


On Mon, Dec 4, 2017 at 6:13 PM, Chris Angelico  wrote:

> On Tue, Dec 5, 2017 at 10:50 AM, Rick Johnson
>  wrote:
> > Chris Angelico wrote:
> >>  wrote:
> >> > Terry Reedy wrote:
> >> >
> >> > [...]
> >> >
> >> >> try:
> >> >>  item = seq[n]
> >> >> except IndexError
> >> >>  do_without_item()
> >> >> else:
> >> >>  process(item)
> >> >>
> >> >> item = seq[n:n+1]
> >> >> if item:
> >> >>  process(item)
> >> >> else:
> >> >>  do_without_item()
> >> >>
> >> >> Many prefer the second.
> >> >
> >> > And they'll prefer it even more when they realize the entire ELSE
> >> > clause of your latter example is superfluous.
> >>
> >> ... how is it superfluous?
> >
> > If the only purpose of an if/else logic structure is to
> > process an arbitrary value _only_ when that value is
> > "truthy", and futhermore, the else clause does nothing of
> > any significance (and in the example provided, appears to
> > be nothing but a placeholder for dead code) then why
> > bother writing the else clause in the first place?
>
> Ahhh, I see how it is. You didn't run the code, ergo you don't
> understand it. Makes perfect sense. :)
>
> Hint: Truthiness is fairly clearly defined here, regardless of the
> value of item.
>
> ChrisA
> --
> https://mail.python.org/mailman/listinfo/python-list
>
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-04 Thread Rick Johnson
On Monday, December 4, 2017 at 6:13:19 PM UTC-6, Chris Angelico wrote:

[...] 

> Ahhh, I see how it is. You didn't run the code, ergo you
> don't understand it. Makes perfect sense. :)

Being that Terry didn't offer any declarations or defintions
for his variables or functions, i assumed, i suppose, like
any other rational person, that it was all just pseudo code.

But, in any event, i don't see how running the code and then
watching helplessly as a volley of NameErrors come rip-
roaring down a stdout stream like a half naked, middle-aged
drunk feller bobbing precariously along a river rapid --
hey, look out for that rock! -- is going to help shed any
light on any of this.

But i suppose it's possible i missed an esoteric joke
somewhere...
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-04 Thread Chris Angelico
On Tue, Dec 5, 2017 at 10:50 AM, Rick Johnson
 wrote:
> Chris Angelico wrote:
>>  wrote:
>> > Terry Reedy wrote:
>> >
>> > [...]
>> >
>> >> try:
>> >>  item = seq[n]
>> >> except IndexError
>> >>  do_without_item()
>> >> else:
>> >>  process(item)
>> >>
>> >> item = seq[n:n+1]
>> >> if item:
>> >>  process(item)
>> >> else:
>> >>  do_without_item()
>> >>
>> >> Many prefer the second.
>> >
>> > And they'll prefer it even more when they realize the entire ELSE
>> > clause of your latter example is superfluous.
>>
>> ... how is it superfluous?
>
> If the only purpose of an if/else logic structure is to
> process an arbitrary value _only_ when that value is
> "truthy", and futhermore, the else clause does nothing of
> any significance (and in the example provided, appears to
> be nothing but a placeholder for dead code) then why
> bother writing the else clause in the first place?

Ahhh, I see how it is. You didn't run the code, ergo you don't
understand it. Makes perfect sense. :)

Hint: Truthiness is fairly clearly defined here, regardless of the
value of item.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-04 Thread Rick Johnson
Chris Angelico wrote:
>  wrote:
> > Terry Reedy wrote:
> >
> > [...]
> >
> >> try:
> >>  item = seq[n]
> >> except IndexError
> >>  do_without_item()
> >> else:
> >>  process(item)
> >>
> >> item = seq[n:n+1]
> >> if item:
> >>  process(item)
> >> else:
> >>  do_without_item()
> >>
> >> Many prefer the second.
> >
> > And they'll prefer it even more when they realize the entire ELSE
> > clause of your latter example is superfluous.
> 
> ... how is it superfluous?

If the only purpose of an if/else logic structure is to
process an arbitrary value _only_ when that value is
"truthy", and futhermore, the else clause does nothing of
any significance (and in the example provided, appears to
be nothing but a placeholder for dead code) then why
bother writing the else clause in the first place?

I'm not questioning Terry's skills here. I'm merely pointing
out that there seems to be no justification for the else
clause in this example.

Indeed, there are valid instances when a decision making
process requires an explicit binary choice (aka: if/else),
but the provided example seems to be saying something more
like this:

# BEGIN CODE (Py2.x, Untested!) ##

if item:
do_something_with(item)
else:
import cons as cons
try:
try:
h = get_handle_for_current_module()
except NameError:
import gvrs_backdoor
h = gvrs_backdoor.force_connection(cons.CURRENT_MODULE)
#
# Assume we have a valid module handle here.
#
with h.request_connection(cons.PYTHON) as py:
py.send_message(cons.EXIT_CONDITIONAL)
except Exception as e:
#
# Alas, now we must wipe the sweat from our brow 
# and accept our unavoidable fate. ':-(
#
# But first! We shall be good stewards and log 
# this error message.
#
msg = e.message
print msg[len(msg):]
del msg
#
# Now: 1. 2.. 3... JUMP!
#
pass

## END CODE ##

Of course, we could have accomplished the same goal -- and
burned a few less processor cycles in the meantime -- by
omitting the superflouous else clause. 

But to each, his or her own, i suppose.

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-04 Thread Cameron Simpson

On 04Dec2017 14:13, Jason Maldonis  wrote:

And I'll be honest -- I like the implementation of the LazyList I wrote
above. I think it's pretty logical, because it allows you to think about
the lazy list like this:  "Treat the list like a norma list. If you run out
of bounds, get more data, then treat the list like a normal list again."
And I really like that clean logic.


Yes, it is very attractive. I've got a buffer class with that behaviour which 
is very useful for parsing data streams.


I think the salient difference between your LazyList's API and my buffer's API 
is that in mine, the space allocation is a distinct operation from the 
__getitem__.


My buffer class keeps an internal buffer of unconsumed data, and its 
__getitem__ indexes only that. It has two methods for "on demand": .extend(), 
which ensures that the internal buffer has at least n bytes, and .take(), which 
does a .extend and then returns the leading n bytes (trimming them from the 
internal buffer of course).


So if I need to inspect the buffer I do a .extend to ensure there's enough 
data, then one can directly use [] to look at stuff, or use .take to grab a 
known size chunk.


The .extend and .take operation accept an optional "short_ok" boolean, default 
False.  When false, .extend and .take raise an exception if there aren't enough 
data available, otherwise they can return with a short buffer containing what 
was available.


That covers your slice situation: true implies Python-like slicing and false 
(the default) acts like you (and I) usually want: an exception.


And it sidesteps Python's design decisions because it leaves the __getitem__ 
semantics unchanged. One ensures the require preconditions (enough data) by 
calling .extend _first_.


Here's some example code parsing an ISO14496 Box header record, which has 2 4 
byte values at the start. The code uses short_ok to probe for immediate 
end-of-input. But if there are data, it uses .extend and .take in default mode 
so that an _incomplete_ record raises an exception:


 def parse_box_header(bfr):
   ''' Decode a box header from the CornuCopyBuffer `bfr`. Return (box_header, 
new_buf, new_offset) or None at end of input.
   '''
   # return BoxHeader=None if at the end of the data
   bfr.extend(1, short_ok=True)
   if not bfr:
 return None
   # note start point
   offset0 = bfr.offset
   user_type = None
   bfr.extend(8)
   box_size, = unpack('>L', bfr.take(4))
   box_type = bfr.take(4)

In summary, I think you should give your LazyList a .extend method to establish 
your code's precondition (enough elements) and then you can proceed with your 
slicing in surety that it will behave correctly.


Cheers,
Cameron Simpson  (formerly c...@zip.com.au)
--
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-04 Thread Chris Angelico
Against my better judgement, I'm going to ask...

On Tue, Dec 5, 2017 at 9:22 AM, Rick Johnson
 wrote:
> Terry Reedy wrote:
>
> [...]
>
>> try:
>>  item = seq[n]
>> except IndexError
>>  do_without_item()
>> else:
>>  process(item)
>>
>> item = seq[n:n+1]
>> if item:
>>  process(item)
>> else:
>>  do_without_item()
>>
>> Many prefer the second.
>
> And they'll prefer it even more when they realize the entire ELSE
> clause of your latter example is superfluous.

... how is it superfluous?

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-04 Thread Rick Johnson
Terry Reedy wrote:

[...]

> try:
>  item = seq[n]
> except IndexError
>  do_without_item()
> else:
>  process(item)
> 
> item = seq[n:n+1]
> if item:
>  process(item)
> else:
>  do_without_item()
> 
> Many prefer the second.  

And they'll prefer it even more when they realize the entire ELSE
clause of your latter example is superfluous.

But there are many usages where the conditional logic is not
needed at all. Sometimes you don't care what you get back
from a slice. Yep, even when the slice is a null string.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-04 Thread Terry Reedy

On 12/4/2017 1:54 PM, Jason Maldonis wrote:

I was extending a `list` and am wondering why slicing lists will never
raise an IndexError, even if the `slice.stop` value if greater than the
list length.



Is there any background on why that doesn't raise an IndexError?


Slicing is perhaps most commonly used on strings, and clamping is 
probably most useful for strings.


Example 1:  s[0:k] gets the k or fewer initial characters of the string, 
perhaps to put in a fixed-width display or storage field.


Example 2: below are two equivalent (I believe) code snippets.

try:
item = seq[n]
except IndexError
do_without_item()
else:
process(item)

item = seq[n:n+1]
if item:
process(item)
else:
do_without_item()

Many prefer the second.  Note that moving process(item) in the first 
into the try clause makes the two non-equivalent.


Example 3:

'if s[k:k+1] in okset' versus 'if len(s) >= k+1 and s[k] in okset'.

There are many examples like this where is slicing did not clamp, the 
user would have to reproduce some of the logic done by slices.


--
Terry Jan Reedy

--
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-04 Thread MRAB

On 2017-12-04 21:22, Jason Maldonis wrote:


>> This is explained in the Python tutorial for strings
>> https://docs.python.org/3/tutorial/introduction.html#strings, as a list
>> is a sequence just like a string it will act in exactly the same way.
>>
>
> The only relevant bit I found in that link is:  "However, out of range
> slice indexes are handled gracefully when used for slicing".  I do
> understand _how_ slices work, but I would really like to know a bit more
> about why slices will never throw out-of-bounds IndexErrors.

That's what "handled gracefully" means. Instead of throwing, they get
clamped.

ChrisA



Cool! Why?   I know I'm being a bit pedantic here, but I truly would like
to understand _why_ slices get clamped.  I've been writing python code
every day for almost 7 years, so usually I can figure stuff like this out,
but I'm struggling here and would really appreciate some insight.


Here's an example:

You have a string of at least n characters.

You want to get the first n characters and leave the remainder.

The first n characters is my_string[ : n].

The remainder is my_string[n : ].

What if len(my_string) == n?

Wouldn't my_string[n : ] raise an IndexError?

Another example:

You want at most n characters of my_string.

What if len(my_string) < n?

my_string[ : n] would raise an IndexError.

You'd need to do my_string[ : min(n, len(my_string))].

Although Python's slicing behaviour doesn't help in your use-case, in 
the majority of cases it does.

--
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-04 Thread Rick Johnson
On Monday, December 4, 2017 at 1:10:01 PM UTC-6, Jason Maldonis wrote:
> I was extending a `list` and am wondering why slicing lists will never
> raise an IndexError, even if the `slice.stop` value if greater than the
> list length.
>
> Quick example:
>
> my_list = [1, 2, 3]
> my_list[:100]  # does not raise an IndexError, but instead returns the full
> list

That's a feature dude, not a bug.

In this case, it only seems illogical because you already
know the extents of the buffer, and that's because you
created it.

However, outside of hand-stiched arts and crafts projects in
the interactive basement of your parent's home, you have no
way of knowing how large a buffer may be in the wild. And
many times, you just need a "transparent slice" from it.

What does "transparent slice" mean, you ask?

Well, for example, (contrived example here) consider a case
where you want the first N chars from a collection of N
strings. In such a case, even if `s[:100]` returns a null
string from the first target, 55 chars from the next target,
99 chars from the next target, and so on and so forth -- you
don't care -- because all you want is a "transparent slice"
of each target string.  And the onerous exception handling
required to deal with disparate buffer lengths would just
get in the way of doing that job _cleanly_.

Now, some might argue that such a feature breaks the Python
Zen. Okay. Let's investigate, shall we>

ZEN SAYS: "SPECIAL CASES ARE NOT SPECIAL ENOUGH TO BREAK THE RULES"

Hmm, with this "feature" being applicable to so many
problems, i would hardly consider it to be a "special case".

Next!

ZEN SAYS: "EXPLICIT IS BETTER THAN IMPLICIT"

Hmm, this one may be difficult to overcome, but we need to
conduct a cost-benefit analysis _first_. And, since i have
not encountered, in my many years of writing Python code,
even one instance of a negative side-effect to this
transparent slicing feature, and, furthermore, i have not
even ~heard~ of one instance of this feature causing havoc,
i will, at this time, and until compelling evidence is
provided to the contrary, conclude that the Zen is wrong in
this case.

*GASP*

Next!

ZEN SAYS: "ALTHOUGH PRACTICALITY BEATS PURITY. ERRORS SHOULD NEVER PASS 
SILENTLY. UNLESS EXPLICITLY SILENCED."

Some might accuse this feature of "masking errors", however,
i don't agree, And while technically speaking --  yes -- a
requested slice range which overlaps the actual physical
boundaries of a target buffer _is_ violating the physical
laws which govern disparate entities existing in a material
universe, code exists beyond the material universe, So this
beef boils down to a petty qualm over semantics.

Next!

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-04 Thread Paul Moore
On 4 December 2017 at 20:13, Jason Maldonis  wrote:
> And I'll be honest -- I like the implementation of the LazyList I wrote
> above. I think it's pretty logical, because it allows you to think about
> the lazy list like this:  "Treat the list like a norma list. If you run out
> of bounds, get more data, then treat the list like a normal list again."
> And I really like that clean logic.

I can't give you a definitive answer as to why slices behave as they
do, any more than anyone else (barring probably Guido). But as a user,
I can say that I find the ability to use slices without checking for
out of bounds cases or handling exceptions to be really convenient.
And one thing Python consistently emphasises is making things easy for
the user, even if that convenience comes at a cost to the implementer.
Certainly, you're a user of the built in list class, but you're using
it to build a wrapper around it, and that makes you a non-core use
case (as I see it). At the end of the day, whether to clamp the values
or raise IndexError is a trade-off in terms of which type of user to
inconvenience, and as I say, in my experience user code wins when that
sort of trade-off comes up.

That's not to say Python makes it deliberately difficult for people
writing code like yours. For your lazy list class, do you know the
maximum amount of data available? If you don't, then supporting
lst[:-1] will be hard, so you're pretty much bound to have to handle
slices differently than built in lists. If you *do* know the maximum
length of the underlying data, then the indices() method of slices
will probably help:

Help on built-in function indices:

indices(...) method of builtins.slice instance
S.indices(len) -> (start, stop, stride)

Assuming a sequence of length len, calculate the start and stop
indices, and the stride length of the extended slice described by
S. Out of bounds indices are clipped in a manner consistent with the
handling of normal slices.

Using indices(), you'll get (from "stop") the amount of data you need to load.

Paul
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-04 Thread Jason Maldonis
>
> >> This is explained in the Python tutorial for strings
> >> https://docs.python.org/3/tutorial/introduction.html#strings, as a list
> >> is a sequence just like a string it will act in exactly the same way.
> >>
> >
> > The only relevant bit I found in that link is:  "However, out of range
> > slice indexes are handled gracefully when used for slicing".  I do
> > understand _how_ slices work, but I would really like to know a bit more
> > about why slices will never throw out-of-bounds IndexErrors.
>
> That's what "handled gracefully" means. Instead of throwing, they get
> clamped.
>
> ChrisA


Cool! Why?   I know I'm being a bit pedantic here, but I truly would like
to understand _why_ slices get clamped.  I've been writing python code
every day for almost 7 years, so usually I can figure stuff like this out,
but I'm struggling here and would really appreciate some insight.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-04 Thread Chris Angelico
On Tue, Dec 5, 2017 at 8:03 AM, Jason Maldonis  wrote:
>>
>> This is explained in the Python tutorial for strings
>> https://docs.python.org/3/tutorial/introduction.html#strings, as a list
>> is a sequence just like a string it will act in exactly the same way.
>>
>
> The only relevant bit I found in that link is:  "However, out of range
> slice indexes are handled gracefully when used for slicing".  I do
> understand _how_ slices work, but I would really like to know a bit more
> about why slices will never throw out-of-bounds IndexErrors.

That's what "handled gracefully" means. Instead of throwing, they get clamped.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-04 Thread Jason Maldonis
>
> This is explained in the Python tutorial for strings
> https://docs.python.org/3/tutorial/introduction.html#strings, as a list
> is a sequence just like a string it will act in exactly the same way.
>

The only relevant bit I found in that link is:  "However, out of range
slice indexes are handled gracefully when used for slicing".  I do
understand _how_ slices work, but I would really like to know a bit more
about why slices will never throw out-of-bounds IndexErrors.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-04 Thread breamoreboy
On Monday, December 4, 2017 at 7:10:01 PM UTC, Jason Maldonis wrote:
> I was extending a `list` and am wondering why slicing lists will never
> raise an IndexError, even if the `slice.stop` value if greater than the
> list length.
> 
> Quick example:
> 
> my_list = [1, 2, 3]
> my_list[:100]  # does not raise an IndexError, but instead returns the full
> list
> 
> Is there any background on why that doesn't raise an IndexError? Knowing
> that might help me design my extended list class better. For my specific
> use case, it would simplify my code (and prevent `if isinstance(item,
> slice)` checks) if the slicing raised an IndexError in the example I gave.

This is explained in the Python tutorial for strings 
https://docs.python.org/3/tutorial/introduction.html#strings, as a list is a 
sequence just like a string it will act in exactly the same way.

--
Kindest regards.

Mark Lawrence.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-04 Thread Jason Maldonis
>Why would this simplify your code? What are you doing that would benefit
>from an IndexError here?

Without simplifying too much, I'm writing a wrapper around a REST API. I
want lazy-loading functionality for lists-of-things, so I am creating a
LazyList class.

This LazyList class will load items as needed, and store them on the list.
When a user triggers `__getitem__`, the LazyList may not yet have data for
the index the user requests, in which case it needs to load more data. I'll
write out the basic functionality of the LazyList class so you can
explicitly see how slicing is impacting the implementation:

class LazyList(list):
def __getitem__(item):
try:
return super().__getitem__(item)
except IndexError:
self._generate_more_data(item)  # If, for example, item == 10,
this function will keep generating more data until there are 10 items in
the list
return super().__getitem__(item)


This works great when `item` is an integer.  However, when `item` is a
slice, the IndexError is never triggered, and so new data will never be
loaded. Consider this snippet:

lazy_list = LazyList()
sublist = lazy_list[:10]

In this case, `sublist` will always be empty, because the first `return
super().__getitem__(item)` "succeeds" by returning an empty list. If
slicing raised an IndexError, the above code would work great.  Instead, I
need to add a check before the try/except to check if the `item` is a
`slice`, and if it is, I need to do bounds checking on the list. It seems a
bit unpythonic to have to do an isinstance check here, so I am wondering if
I am missing something important about why slices don't raise IndexErrors.

And I'll be honest -- I like the implementation of the LazyList I wrote
above. I think it's pretty logical, because it allows you to think about
the lazy list like this:  "Treat the list like a norma list. If you run out
of bounds, get more data, then treat the list like a normal list again."
And I really like that clean logic.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-04 Thread Jason Maldonis
>
> Have you ever used a language that does that?

I have.
> The String class in the C# language does that, and it's /really/ annoying.
> I have to add extra code to prevent such exceptions.
> In practice, I find that the way that Python does it is much nicer. (And
> Python isn't unique in this respect, either.)
>

I'm not here to criticize one way or the other, just understand. As far as
I'm aware, I don't rely on python's slicing functionality allowing indexes
that are over the length of a list. But I'm just one person and I'm sure
there are many other use cases I'm not thinking about. If you think what
you wrote is a good explanation for why slicing doesn't raise IndexErrors
in python, I'd be interesting in seeing some of your use cases about when
you had to explicitly check bounds of list slices in C#.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-04 Thread MRAB

On 2017-12-04 18:54, Jason Maldonis wrote:

I was extending a `list` and am wondering why slicing lists will never
raise an IndexError, even if the `slice.stop` value if greater than the
list length.

Quick example:

my_list = [1, 2, 3]
my_list[:100]  # does not raise an IndexError, but instead returns the full
list

Is there any background on why that doesn't raise an IndexError? Knowing
that might help me design my extended list class better. For my specific
use case, it would simplify my code (and prevent `if isinstance(item,
slice)` checks) if the slicing raised an IndexError in the example I gave.


Have you ever used a language that does that?

I have.

The String class in the C# language does that, and it's /really/ annoying.

I have to add extra code to prevent such exceptions.

In practice, I find that the way that Python does it is much nicer. (And 
Python isn't unique in this respect, either.)

--
https://mail.python.org/mailman/listinfo/python-list


Re: why won't slicing lists raise IndexError?

2017-12-04 Thread Random832
On Mon, Dec 4, 2017, at 13:54, Jason Maldonis wrote:
> Is there any background on why that doesn't raise an IndexError? Knowing
> that might help me design my extended list class better. For my specific
> use case, it would simplify my code (and prevent `if isinstance(item,
> slice)` checks) if the slicing raised an IndexError in the example I
> gave.

Slicing (of strings, lists, tuples, anyway) never raises an IndexError.
If the start is out of range it will return an empty list. I don't know.
As for "why", it's just how the operation was designed. Perhaps it was
considered that an exception isn't needed because there's no ambiguity
(i.e. there's no other reason a slice operation can return a list
shorter than the length implied by the slice parameters).

Why would this simplify your code? What are you doing that would benefit
from an IndexError here?
-- 
https://mail.python.org/mailman/listinfo/python-list


why won't slicing lists raise IndexError?

2017-12-04 Thread Jason Maldonis
I was extending a `list` and am wondering why slicing lists will never
raise an IndexError, even if the `slice.stop` value if greater than the
list length.

Quick example:

my_list = [1, 2, 3]
my_list[:100]  # does not raise an IndexError, but instead returns the full
list

Is there any background on why that doesn't raise an IndexError? Knowing
that might help me design my extended list class better. For my specific
use case, it would simplify my code (and prevent `if isinstance(item,
slice)` checks) if the slicing raised an IndexError in the example I gave.
-- 
https://mail.python.org/mailman/listinfo/python-list