Why does list have no 'get' method?

D

Denis Bilenko

Why does list have no 'get' method with exactly the same semantics as
dict's get,
that is "return an element if there is one, but do NOT raise
an exception if there is not.":

def get(self, item, default = None):
try:
return self[item]
except IndexError:
return default

It is often desirable, for example, when one uses the easiest
command-line options parsing - based on absolute positions:

With such a method instead of this (snippet from BaseHTTPServer.py)

if sys.argv[1:]:
port = int(sys.argv[1])
else:
port = 8000

we could write

port = sys.argv.get(1) or 8000

which is both more condense and more clear.

The change is unlikely to break anyone's code.
(nobody uses getattr(obj, 'get') to distinguish between lists and dicts, right?)
 
P

Paul Rubin

Denis Bilenko said:
port = sys.argv.get(1) or 8000

I like the suggestion, except it should be

port = int(sys.argv.get(1, '8000'))

one could imagine your example going wrong in a protocol where 0 is
a valid port number.
 
R

Raymond Hettinger

[Denis Bilenko]
Why does list have no 'get' method with exactly the same semantics as
dict's get,
that is "return an element if there is one, but do NOT raise
an exception if there is not.": . . .
It is often desirable, for example, when one uses the easiest
command-line options parsing - based on absolute positions:

With such a method instead of this (snippet from BaseHTTPServer.py)

    if sys.argv[1:]:
        port = int(sys.argv[1])
    else:
        port = 8000

we could write

    port = sys.argv.get(1) or 8000

At first blush that example would make it seem like a good idea, but I
don't see how the example could extend past the first index. If the
port argument is optional, how would you know the index position of
optional arguments to follow?

With a dictionary, one could plausibly write:

host = d.get('host', 'http://example.com')
port = d.get('port', 8080)
path = d.get('path', '/')

But would this make sense with a list:

host = s.get(0, 'http://example.com')
port = d.get(1, 8080)
path = d.get(2, '/')

If positions 0 and 1 are optional, how do you expect to know whether
"path" is going to be at position 2? This problem doesn't exist with
dictionaries because the presence or absence of optional entries does
not affect the key reference to other entries. Accordingly, I
wouldn't expect that dict.get() would have a parallel list.get() with
plausible use cases.

Raymond
 
B

bearophileHUGS

Paul Rubin:
I like the suggestion, except it should be
port = int(sys.argv.get(1, '8000'))
one could imagine your example going wrong in a protocol where 0 is
a valid port number.

I think a high-level language like Python must have boolean operators
(or and not) that behave in a much more clean way, with a simpler
semantics. That is they have to return only true or false. Otherwise
they are just a source of bugs and confusion. This is a change fit for
Python 3.
That trick with or/and may look good for Perl, but it's unfit for a
language that tries to be clear, readable from people that don't know
it much, and good to learn to program. Python has now the if-then
expression too that is more clear.

Bye,
bearophile
 
S

Stefan Behnel

Paul Rubin:

I think a high-level language like Python must have boolean operators
(or and not) that behave in a much more clean way, with a simpler
semantics. That is they have to return only true or false. Otherwise
they are just a source of bugs and confusion. This is a change fit for
Python 3.

Conditional expressions have clear semantics.

Stefan
 
S

Steven D'Aprano

I think a high-level language like Python must have boolean operators
(or and not) that behave in a much more clean way, with a simpler
semantics. That is they have to return only true or false. Otherwise
they are just a source of bugs and confusion.

Well, that's one opinion.

Boolean operators can be complicated to understand if you write
complicated expressions, or if you don't understand what they do. But
otherwise, they're no more complicated than arithmetic expressions.

[...]
That trick with or/and may look good for Perl, but it's unfit for a
language that tries to be clear, readable from people that don't know it
much, and good to learn to program. Python has now the if-then
expression too that is more clear.

Suppose I have two lists, and want to process the first one if it is not
empty, otherwise process the second. I'd write it like this:

process(mylist or yourlist)

You're suggesting I should write it like this:

process(mylist if mylist else yourlist)


With the greatest respect, I think that if you think the second example
"is more clear", you're completely bonkers. *grins*
 
B

bearophileHUGS

Steven D'Aprano:
With the greatest respect, I think that if you think the second example
"is more clear", you're completely bonkers. *grins*

No one is completely normal, I presume :)
I'd like to know what others think about it, about this anti-feature.
What I can say is that other computer languages too think that boolean
operations must return boolean values only, so I am not alone in my
folly :)

Bye,
bearophile
 
A

Arnaud Delobelle

Paul Rubin:


I think a high-level language like Python must have boolean operators
(or and not) that behave in a much more clean way, with a simpler
semantics. That is they have to return only true or false. Otherwise
they are just a source of bugs and confusion. This is a change fit for
Python 3.
That trick with or/and may look good for Perl, but it's unfit for a
language that tries to be clear, readable from people that don't know
it much, and good to learn to program. Python has now the if-then
expression too that is more clear.

Bye,
bearophile

Personally, between

* foo if foo else bar
* foo or bar

I prefer the second. Maybe it could be spelt

* foo else bar ?

Moreover between the following two:

* foores = foo()
foobar = foores if foores else bar

* foobar = foo() or bar

I also prefer the second. Maybe it could be spelt

* foo() else bar ?

I have not thought of parsing issues :)
 
T

Thomas Bellman

Bruno Desthuilliers said:
Not quite. In C and a couple other langages, int 0 is false, anything
else is true.

Not just int, but all kinds of integers, as well as all kinds of
floating point types and all kinds of pointers, with the value 0
are considered false. And structs and unions can't be used in a
boolean context at all, and are thus neither true nor false.
In Lisp (and IIRC), an empty list is false, anything else
is true.

There seems to be a language name missing from the parenthesis.
Were you perhaps thinking of Scheme? If so, then no, in Scheme
only #f is false, and the empty list () is considered true.
 
B

Bruno Desthuilliers

(e-mail address removed) a écrit :
Steven D'Aprano:

No one is completely normal, I presume :)
I'd like to know what others think about it, about this anti-feature.
s/anti//

What I can say is that other computer languages too think that boolean
operations must return boolean values only,

Not quite. In C and a couple other langages, int 0 is false, anything
else is true. In Lisp (and IIRC), an empty list is false, anything else
is true. I'm sure someone else could come with more than a couple other
non-cryptic langages that just don't have a proper boolean type.

Using "emptyness" as a false value in boolean expressions is not that
uncommon, and it has proven so far to be a working solution. Also,
returning the tested object instead of a bool just makes sens to me.
FWIW, booleans are a late addition to Python, and quite a couple persons
where worried that it would only lead to confusion.
 
S

Steve Holden

Steven D'Aprano:
It's amusing how often "with the greatest respect" is used to preface a
statement that clearly implies very little respect at all. Though, for
what it's worth, I agree with Steven here.
No one is completely normal, I presume :)
I'd like to know what others think about it, about this anti-feature.
What I can say is that other computer languages too think that boolean
operations must return boolean values only, so I am not alone in my
folly :)
Other languages do indeed refuse the temptation to short-circuit, but
that doesn't mean that Python is wrong to do so. It's a design choice,
and while you are free to disagree with it I imagine you would be
pissing in the wind in attempting to get a change like that into Python 3.

Most people like the semantics of "and" and "or" as they are.

no-more-normal-than-anyone-else-ly y'rs - steve
 
B

Bruno Desthuilliers

Thomas Bellman a écrit :
(snip)

There seems to be a language name missing from the parenthesis.

Yes, sorry - I was thinking of OCaml and/or Haskell, but couldn't
remember which so I cout this out but forgot the (and IIRC).
 
W

Wildemar Wildenburger

Arnaud said:
Personally, between

* foo if foo else bar
* foo or bar

I prefer the second. Maybe it could be spelt

* foo else bar ?
How about

val = foo rather than bar

If that is not clear and obvios, I don't know what is. ;)

/W
 
S

Steve Holden

Wildemar said:
How about

val = foo rather than bar

If that is not clear and obvios, I don't know what is. ;)
Even clearer:

ASSIGN foo IF foo HAS A VALUE, OTHERWISE bar, TO val

Ahh, the joys of the COmmon Business Oriented Language.

regards
Steve
 
M

Michael Spencer

Wildemar said:
How about

val = foo rather than bar

If that is not clear and obvios, I don't know what is. ;)

/W
Excellent suggestion, and obviously its semantics should be:

val = foo if bar else foo

and so, some might argue for:

val = foo despite bar

which would allow more aggressive short-circuiting. However, I'm not sure how
useful this is in practice.

M
 
S

Steven D'Aprano

How about

val = foo rather than bar

If that is not clear and obvios, I don't know what is. ;)

In English, the expression "foo rather than bar" means "bar is never
chosen, foo is always chosen".

Oh, and if you think it's hard convincing Guido to add one new keyword,
wait until you try to get him to add TWO.
 
G

George Sakkis

In English, the expression "foo rather than bar" means "bar is never
chosen, foo is always chosen".

Ok, the fix is easy:

val = BETTER foo THAN bar

;-)


Cobol-strikes-back-ly yours,

George
 
G

Gabriel Genellina

En Thu, 07 Feb 2008 19:36:57 -0200, George Sakkis
Ok, the fix is easy:

val = BETTER foo THAN bar

Great! It could even be qualified:

val = BETTER foo THAN bar UNLESS not required(foo)

and nested:

val = BETTER foo THAN (
BETTER bar THAN baz
UNLESS lunar_phase=="Full Moon")

and used wherever any other expression is allowed:

val = BETTER foo THAN (
BETTER bar THAN baz
UNLESS insanity_level>threshold)
UNLESS self.parent is self \
if verbose else 42

Sane precedence rules would require using ( ) around the expression before
the if clause, I presume.

Eagerly awaiting the implementation,
 
C

Carl Banks

Other languages do indeed refuse the temptation to short-circuit,

Short-circuiting isn't the issue here; a language can short circuit
and still return a boolean.
but
that doesn't mean that Python is wrong to do so. It's a design choice,
and while you are free to disagree with it I imagine you would be
pissing in the wind in attempting to get a change like that into Python 3.

Most people like the semantics of "and" and "or" as they are.


I guess I'll agree with bearophile here; I think booleans should be
completely disjoint from all other types, as they are in Java. "and",
"or", and "not" should accept only boolean operands and return only
boolean results.

I don't deny that it's convenient to use "or" that returns the first
true value, or that it's sometimes a marginal improvement in clarity.

I just think this idiom is too error prone, and very often too
misleading, to justify its convenience. There's ordinary
carelessness, of course, where someone writes a function like this:

def op(datum=None):
result = datum or default

while not stopping to consider that the empty string would be a legal
value for datum in this case. But there's a more insidious danger
that can't be chalked up to carelessness: when the acceptable values
for datum change *after* the function is written. This leads to
subtle breakage.

As far as the user is concerned, this function's correct behavior is
to "use the default when the argument is not specified", but as-is the
function is not robust to future changes or uses. The function is a
poor, non-robust implementation of the desired behavior.

To me this feels like a ticking bomb, a bug waiting to emerge from
it's egg.


More generally: I find that the boundary between what Python considers
to be true and false rarely corresponds exactly to what I'm trying to
do in cases like the above.
Usually the true/false test only works for certain set of expected
values that I have in my mind. When the acceptable values are
generalized, when you want to expand this function's role, does the
true/false test still work? I find it rarely does.


The Python treatment of booleans is, by far, my biggest gripe with
Python. (Which, you know, is a pretty good thing to have as a biggest
gripe.)


Carl Banks
 
C

cokofreedom

Short-circuiting isn't the issue here; a language can short circuit
and still return a boolean.



I guess I'll agree with bearophile here; I think booleans should be
completely disjoint from all other types, as they are in Java. "and",
"or", and "not" should accept only boolean operands and return only
boolean results.

I don't deny that it's convenient to use "or" that returns the first
true value, or that it's sometimes a marginal improvement in clarity.

I just think this idiom is too error prone, and very often too
misleading, to justify its convenience. There's ordinary
carelessness, of course, where someone writes a function like this:

def op(datum=None):
result = datum or default

while not stopping to consider that the empty string would be a legal
value for datum in this case. But there's a more insidious danger
that can't be chalked up to carelessness: when the acceptable values
for datum change *after* the function is written. This leads to
subtle breakage.

As far as the user is concerned, this function's correct behavior is
to "use the default when the argument is not specified", but as-is the
function is not robust to future changes or uses. The function is a
poor, non-robust implementation of the desired behavior.

To me this feels like a ticking bomb, a bug waiting to emerge from
it's egg.

More generally: I find that the boundary between what Python considers
to be true and false rarely corresponds exactly to what I'm trying to
do in cases like the above.
Usually the true/false test only works for certain set of expected
values that I have in my mind. When the acceptable values are
generalized, when you want to expand this function's role, does the
true/false test still work? I find it rarely does.

The Python treatment of booleans is, by far, my biggest gripe with
Python. (Which, you know, is a pretty good thing to have as a biggest
gripe.)

Carl Banks

Can't you just make a subclass of Boolean and add methods to the true/
false, or am i running up a tree with a cat?

I think a clear problem with this is that, this is one area of grief
for some users with the Try/Except: clause usage, there are many other
examples of this where people would prefer one liners, and a good
argument not to allow one is because then you probably wouldn't have a
good defence against disallowing the other forms...

just-my-one-cent-ly's yours Coko
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,073
Latest member
DarinCeden

Latest Threads

Top