niXforums Forum Index
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   PreferencesPreferences   Log in to check your private messagesLog in to check your private messages   Log inLog in 
· nixdoc.net · man pages · Linux HOWTOs · FreeBSD Tips · Forums
navigation Forum index » Programming » python
Coding style
Post new topic   Reply to topic Page 3 of 6 [86 Posts] View previous topic :: View next topic
Goto page:  Previous  1, 2, 3, 4, 5, 6 Next
Author Message
Lawrence D'Oliveiro
*nix forums Guru


Joined: 25 Mar 2005
Posts: 723

PostPosted: Tue Jul 18, 2006 6:46 am    Post subject: Re: Coding style Reply with quote

In message <Q8OdnfqZn6udnSHZnZ2dnUVZ_vOdnZ2d@nmt.edu>, Bob Greschke wrote:

Quote:
I'd go even one step further. Turn it into English (or your favorite
non-computer language):

1. While list, pop.

2. While the length of the list is greater than 0, pop.

Which one makes more sense? Guess which one I like. CPU cycles be
damned.
Smile

One of my rules is, always program like the language actually has a Boolean
type, even if it doesn't. That means, never assume that arbitrary values
can be interpreted as true or false, always put in an explicit comparison
if necessary so it's obvious the expression is a Boolean.
Back to top
Peter Otten
*nix forums Guru


Joined: 20 Feb 2005
Posts: 464

PostPosted: Tue Jul 18, 2006 7:28 am    Post subject: Re: Coding style Reply with quote

Carl Banks wrote:

Quote:

Peter Otten wrote:
Carl Banks wrote:

def process_values(lst):
if not lst:
return
do_expensive_initialization_step()
for item in lst:
do_something_with(item)
do_expensive_finalization_step()

What if you called the function like this:

process_values(x.strip() for x in values_lst)

Oops, now we've just gone through an expensive initialization and
finalization for nothing (since values_lst was empty). Maybe some
subtle bugs introduced. If we're lucky, the finalization step will
throw an exception.

The good news is that the above has a 99 percent chance that it just
works with iterators/generators -- even though the writer may not have
been aware of them/they didn't exist when the code was written...

There's a litmus test I like to use when justifying something with
percentages: I imagine that I'm presenting it to my boss, and ask
myself if I still expect to have a job the next day. Smile

That 99 percent chance is not meant to exempt you from actually verifying
that it works. Docstrings can do wonders here

def process_values(lst):
"Foos all bars in a list"

vs

def process_values(lst):
"Foos all bars in an iterable"

If in doubt, pass a list (-comprehension) as there are other ways of quiet
failure (the function may loop twice over its argument).

Quote:
Yes, I agree with you, it most cases I expect merely unnecessary work.
(Which is not the best news; the best news would be an exception right
away.) That's why I think this is only a "pretty good" reason to use
"if len(lst)>0", not a slam dunk.

If process_values() were /aware/ of iterators it would probably be written

def process_values(items):
first_pass = True
for item in items:
if first_pass:
do_expensive_initialization_step()
first_pass = False
do_something_with(item)
if not first_pass:
do_expensive_finalization_step()

or just with an additional

items = list(items)

as its first statement.

Peter
Back to top
bruno modulix
*nix forums Guru


Joined: 21 Feb 2005
Posts: 819

PostPosted: Tue Jul 18, 2006 8:45 am    Post subject: Re: Coding style Reply with quote

tac-tics wrote:
Quote:
Or even just:

lst = []

;-)


Indeed.

I'd say the second one.

And you'd be plain wrong.

Quote:
Empty lists are not false.

In a bolean context, empty containers (lists, tuples, dicts, sets etc),
empty strings, integer 0, float 0.0 and None are all false. This is part
of the language specs.

--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'onurb@xiludom.gro'.split('@')])"
Back to top
bruno modulix
*nix forums Guru


Joined: 21 Feb 2005
Posts: 819

PostPosted: Tue Jul 18, 2006 8:54 am    Post subject: Re: Coding style Reply with quote

tac-tics wrote:
Quote:
dwelch91 wrote:

tac-tics wrote:

I'd say the second one. Empty lists are not false. They are empty. Long
live dedicated boolean data types.


Uh, no, empty lists are False in a boolean context:

http://docs.python.org/lib/truth.html

-Don


Perhaps I should have specified it like this:


empty_list = []
empty_list is not False

True

Physical identity is not structural equality.


Quote:
I'm well aware that both of these snippets does the same thing. I'm
just spouting my opinion that lists and integers are not tests, and in
an ideal world (Java??? X-)

You naughty troll

Quote:
if statements support only boolean types.

if statements supports only boolean *expressions*. An expression is
boolean if it's result can be coerced to a boolean value, ie fed to the
bool type's constructor. So your example is wrong wrt/ if statements -
it should read:

empty_list = []
bool(empty_list) is False
=> True


--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'onurb@xiludom.gro'.split('@')])"
Back to top
bruno modulix
*nix forums Guru


Joined: 21 Feb 2005
Posts: 819

PostPosted: Tue Jul 18, 2006 8:58 am    Post subject: Re: Coding style Reply with quote

dwelch91 wrote:
Quote:
PTY wrote:

Which is better?

lst = [1,2,3,4,5]

while lst:
lst.pop()

OR

while len(lst) > 0:
lst.pop()


I think the first one is better, but if all you are doing is removing
all the items in the list, this is definitely better:

lst = []

Not if there are other names bound to the same list. You are only
rebinding this name, which does *not* empty the list object. The correct
solution here is

del lst[:]

which will remove all content from the list object,



--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'onurb@xiludom.gro'.split('@')])"
Back to top
bruno modulix
*nix forums Guru


Joined: 21 Feb 2005
Posts: 819

PostPosted: Tue Jul 18, 2006 9:17 am    Post subject: Re: Coding style Reply with quote

PTY wrote:
Quote:
Bob Greschke wrote:

rurpy@yahoo.com> wrote in message
news:1153168968.995422.198360@m73g2000cwd.googlegroups.com...

PTY wrote:

Which is better?

lst = [1,2,3,4,5]

while lst:
lst.pop()

OR

while len(lst) > 0:
lst.pop()

A dozen posts, but nobody has posted the right
answer yet, so I will :-)

It doesn't matter -- use whichever you prefer (*)
This is an angels on the head of a pin issue.

(*) -- If your code is part of an existing body of
code that uses one or the other style consistently,
then you should do the same.


I'd go even one step further. Turn it into English (or your favorite
non-computer language):

1. While list, pop.

2. While the length of the list is greater than 0, pop.

Which one makes more sense? Guess which one I like. CPU cycles be damned.
:)

Bob



It looks like there are two crowds, terse and verbose.

Nope, there are two crowds: those who RTFM, and those who don't.

Quote:
I thought terse
is perl style and verbose is python style.

s/terse/cryptic/
s/verbose/readable/

Python is much more readable than Java because it's *less* verbose than
Java.

Quote:
BTW, lst = [] was not what
I was interested in Smile

Nor is it the correct functional equivalent of your code snippet.

Quote:
I was asking whether it was better style to
use len() or not.

The idiomatic solution is clearly derivable from Python's language
documentation : in a boolean context, empty lists (etc...) eval to
False. FWIW, it's also more generic (you could have an object supporting
pop() but not __len__()), less error-prone, and can allow optimisations
(a container may know that it is empty without computing it's length).


--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'onurb@xiludom.gro'.split('@')])"
Back to top
bruno modulix
*nix forums Guru


Joined: 21 Feb 2005
Posts: 819

PostPosted: Tue Jul 18, 2006 9:23 am    Post subject: Re: Coding style Reply with quote

Carl Banks wrote:
Quote:
Patrick Maupin wrote:

PTY wrote:


It looks like there are two crowds, terse and verbose. I thought terse
is perl style and verbose is python style. BTW, lst = [] was not what
I was interested in Smile I was asking whether it was better style to
use len() or not.

It's not canonical Python to use len() in this case. From PEP 8:

- For sequences, (strings, lists, tuples), use the fact that empty
sequences are false.

Yes: if not seq:
if seq:

No: if len(seq)
if not len(seq)

The whole reason that a sequence supports testing is exactly for this
scenario. This is not an afterthought -- it's a fundamental design
decision of the language.


That might have made sense when Python and string, list, tuple were the
only sequence types around.

Nowadays, Python has all kinds of spiffy types like numpy arrays,
interators, generators,
etc., for which "empty sequence is false" just
doesn't make sense.

Iterators and generators are *not* sequences types. wrt/ non-builtin
container types, I suggest you re-read section 3.3.1 of the language
references:

"""
__nonzero__( self)
Called to implement truth value testing, and the built-in operation
bool(); should return False or True, or their integer equivalents 0 or
1. When this method is not defined, __len__() is called, if it is
defined (see below). If a class defines neither __len__() nor
__nonzero__(), all its instances are considered true.
"""
http://docs.python.org/ref/customization.html


Quote:
If Python had been designed with these types in
mind, I'm not sure "empty list is false" would have been part of the
language, let alone recommend practice.

FWIW, this magic method already existed in 1.5.2 :
http://www.python.org/doc/1.5.2p2/ref/customization.html


--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'onurb@xiludom.gro'.split('@')])"
Back to top
bruno modulix
*nix forums Guru


Joined: 21 Feb 2005
Posts: 819

PostPosted: Tue Jul 18, 2006 9:30 am    Post subject: Re: Coding style Reply with quote

Lawrence D'Oliveiro wrote:
Quote:
In message <Q8OdnfqZn6udnSHZnZ2dnUVZ_vOdnZ2d@nmt.edu>, Bob Greschke wrote:


I'd go even one step further. Turn it into English (or your favorite
non-computer language):

1. While list, pop.

2. While the length of the list is greater than 0, pop.

Which one makes more sense? Guess which one I like. CPU cycles be
damned.
:)


One of my rules is, always program like the language actually has a Boolean
type, even if it doesn't.

Python has a boolean type.

Quote:
That means, never assume that arbitrary values
can be interpreted as true or false,

There's nothing to assume, and nothing arbitrary in it. It's all clearly
defined in whole letters in the language references.

Quote:
always put in an explicit comparison
if necessary so it's obvious the expression is a Boolean.

The fact that the expression is used in the context of a if statement is
clearly enough to denote a boolean expression. Explicitly testing
against a boolean is uselessly redundant - and doesn't change anything,
since it's always a boolean expression. FWIW, getting rid of theses
"explicit" redundant tests was one of the first things I learned about
programming.


--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'onurb@xiludom.gro'.split('@')])"
Back to top
pavlovevidence@gmail.com
*nix forums beginner


Joined: 17 Jul 2006
Posts: 17

PostPosted: Tue Jul 18, 2006 11:53 am    Post subject: Re: Coding style Reply with quote

Bruno Desthuilliers wrote:
Quote:
Carl Banks wrote:
Patrick Maupin wrote:

PTY wrote:


It looks like there are two crowds, terse and verbose. I thought terse
is perl style and verbose is python style. BTW, lst = [] was not what
I was interested in Smile I was asking whether it was better style to
use len() or not.

It's not canonical Python to use len() in this case. From PEP 8:

- For sequences, (strings, lists, tuples), use the fact that empty
sequences are false.

Yes: if not seq:
if seq:

No: if len(seq)
if not len(seq)

The whole reason that a sequence supports testing is exactly for this
scenario. This is not an afterthought -- it's a fundamental design
decision of the language.


That might have made sense when Python and string, list, tuple were the
only sequence types around.

Nowadays, Python has all kinds of spiffy types like numpy arrays,
interators, generators,
etc., for which "empty sequence is false" just
doesn't make sense.

Iterators and generators are *not* sequences types. wrt/ non-builtin
container types, I suggest you re-read section 3.3.1 of the language
references:

I'm aware of the semantics, thank you, and that they're as advertised
in the docs. It doesn't matter whether you call it a sequence or not.
Iterables, lists, arrays, and whatever else have overlapping uses, but
bool(obj) behaves differently for different types, making it unsuitable
for writing generic functions that might use some other types that
aren't vanilla list, tuple, and string.

All I'm saying is, knowing there's lots of roughly-list-like types that
don't consider "empty" to be "false", and that there's not reasonable
way to get consistent behavior as to what the boolean value of such
types is, it's possible that these types wouldn't even have a boolean
value and any tests for emptiness would have to be explicit.

But who knows? Maybe this is just one case where brevity trumps
everything else.


Carl BAnks
Back to top
bruno modulix
*nix forums Guru


Joined: 21 Feb 2005
Posts: 819

PostPosted: Tue Jul 18, 2006 1:40 pm    Post subject: Re: Coding style Reply with quote

Carl Banks wrote:
Quote:
Bruno Desthuilliers wrote:

Carl Banks wrote:

Patrick Maupin wrote:


PTY wrote:



It looks like there are two crowds, terse and verbose. I thought terse
is perl style and verbose is python style. BTW, lst = [] was not what
I was interested in Smile I was asking whether it was better style to
use len() or not.

It's not canonical Python to use len() in this case. From PEP 8:

- For sequences, (strings, lists, tuples), use the fact that empty
sequences are false.

Yes: if not seq:
if seq:

No: if len(seq)
if not len(seq)

The whole reason that a sequence supports testing is exactly for this
scenario. This is not an afterthought -- it's a fundamental design
decision of the language.


That might have made sense when Python and string, list, tuple were the
only sequence types around.

Nowadays, Python has all kinds of spiffy types like numpy arrays,
interators, generators,
etc., for which "empty sequence is false" just
doesn't make sense.

Iterators and generators are *not* sequences types. wrt/ non-builtin
container types, I suggest you re-read section 3.3.1 of the language
references:


I'm aware of the semantics, thank you, and that they're as advertised
in the docs. It doesn't matter whether you call it a sequence or not.

Your opinion - not mine. Sequences are iterable, but not all iterables
are sequences.

Quote:
Iterables, lists, arrays, and whatever else have overlapping uses, but
bool(obj) behaves differently for different types,

bool(obj) will mainly look for __len__(), then for __nonzero__(), then
return True. You can only call len(obj) on objects implementing
__len__(), so relying on (implicit) 'bool(obj)' is clearly more generic
than 'len(obj) > 0'. Also, since bool(obj) will try to call
obj.__len__(), explicitely calling len(obj) doesn't make any difference.

Quote:
making it unsuitable
for writing generic functions that might use some other types that
aren't vanilla list, tuple, and string.

Using an explicit test against the length of an iterator or generator
*won't* work anyway, since iterators and generators are unsized. And
that's one of the reasons why the difference between sequences and
iterables does matter.

And if you want your own sequence types to be well-behaved sequence
types, just take time to implement the needed protocol(s), including
__len__().

For short: either your function expects an iterable or it expects a
sequence. If it expects an iterable, treat it as an iterable wether it
happens to be a sequence or not. If it expects a sequence, it obviously
won't work with a non-sequence.

Quote:
All I'm saying is, knowing there's lots of roughly-list-like

"roughly-list-like" ?

Quote:
types that
don't consider "empty" to be "false",

This means they are unsized (ie don't implement __len__).

Quote:
and that there's not reasonable
way to get consistent behavior as to what the boolean value of such
types is,

I don't know what "types" you are talkink about, but seems like either
they're not designed to be treated as sequences or they are badly
implemented. In the first case, you're not using them correctly. In the
second case, send a bug report to the authors.

Quote:
it's possible that these types wouldn't even have a boolean
value and any tests for emptiness would have to be explicit.

Yes ? How ? Calling len() on them ?-)
(hint: reread how len() and bool() works wrt/ __len__())



--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'onurb@xiludom.gro'.split('@')])"
Back to top
pavlovevidence@gmail.com
*nix forums beginner


Joined: 17 Jul 2006
Posts: 17

PostPosted: Tue Jul 18, 2006 2:25 pm    Post subject: Re: Coding style Reply with quote

Bruno Desthuilliers wrote:
Quote:
Carl Banks wrote:
Iterables, lists, arrays, and whatever else have overlapping uses, but
bool(obj) behaves differently for different types,

bool(obj) will mainly look for __len__(), then for __nonzero__(), then
return True. You can only call len(obj) on objects implementing
__len__(), so relying on (implicit) 'bool(obj)' is clearly more generic
than 'len(obj) > 0'. Also, since bool(obj) will try to call
obj.__len__(), explicitely calling len(obj) doesn't make any difference.

I'm well aware of Python's semantics, and it's irrelvant to my
argument. What low level operations it does do not concern me. I'm
concerned about what equats to "truth". For generators and such, it's
"always". For lists, it's "empty". For numpy arrays, there is no
truth value.

For the purpose of writing generic functions, this is inconsistent.
And, IMO, it's possible that the language would have been designed
differently (by not letting them have any truth value) if they'd been
around in the beginning.


Quote:
And if you want your own sequence types to be well-behaved sequence
types, just take time to implement the needed protocol(s), including
__len__().

You know very well that not all iterables can know their length ahead
of time.


Quote:
For short: either your function expects an iterable or it expects a
sequence. If it expects an iterable, treat it as an iterable wether it
happens to be a sequence or not.

1. This is fine in a perfect world where all code clearly conforms to
expectation. Problem is, a lot doesn't. I think it's quite easy to
accidentally check something intended as an iterable for emptiness.
And, as I've explained in other posts, this can lead to subtle bugs.
Whereas if you check for emptiness using len, it throws an exception
right away, no bugs. It's safer to use len. (Safest of all is not to
check for emptiness at all.)

2. This logic doesn't work for numpy arrays. In a lot of cases, a
function expecting a list works perfectly fine if you pass it a numpy
arrray. But, if you were to write such a function with "if lst"
instead of "if len(lst)>0", it's guaranteed to fail. The function is
more generic with the len test.


Quote:
it's possible that these types wouldn't even have a boolean
value and any tests for emptiness would have to be explicit.

Yes ? How ? Calling len() on them ?-)
(hint: reread how len() and bool() works wrt/ __len__())

Yes. If the language had been designed such that a list had no
nb_nonzero slot, you'd have to check for emptiness with len. Perhaps
you're missing some of the nuances of English verb tenses (don't feel
too bad, it's hard). I'm not arguing "what is", I'm arguing what
"could have been if circumstances were different". If the language
were designed differently, then the rules would be different.


Carl Banks
Back to top
bruno modulix
*nix forums Guru


Joined: 21 Feb 2005
Posts: 819

PostPosted: Tue Jul 18, 2006 3:04 pm    Post subject: Re: Coding style Reply with quote

Carl Banks wrote:
Quote:
Bruno Desthuilliers wrote:

Carl Banks wrote:

Iterables, lists, arrays, and whatever else have overlapping uses, but
bool(obj) behaves differently for different types,

bool(obj) will mainly look for __len__(), then for __nonzero__(), then
return True. You can only call len(obj) on objects implementing
__len__(), so relying on (implicit) 'bool(obj)' is clearly more generic
than 'len(obj) > 0'. Also, since bool(obj) will try to call
obj.__len__(), explicitely calling len(obj) doesn't make any difference.


I'm well aware of Python's semantics, and it's irrelvant to my
argument. What low level operations it does do not concern me. I'm
concerned about what equats to "truth". For generators and such, it's
"always".

"generators and such" are not sequences.

Quote:
For lists, it's "empty". For numpy arrays, there is no
truth value.

Then treat numpy arrays as iterables (which they are), not as sequences.

Quote:
For the purpose of writing generic functions, this is inconsistent.

Not if you choose to design your function to work on iterables (which
means you don't use len() at all to test for emptiness).

Quote:
And, IMO, it's possible that the language would have been designed
differently (by not letting them have any truth value) if they'd been
around in the beginning.



And if you want your own sequence types to be well-behaved sequence
types, just take time to implement the needed protocol(s), including
__len__().


You know very well that not all iterables can know their length ahead
of time.

Yes, but I was talking about *sequences*, not iterables.

Quote:

For short: either your function expects an iterable or it expects a
sequence. If it expects an iterable, treat it as an iterable wether it
happens to be a sequence or not.


1. This is fine in a perfect world where all code clearly conforms to
expectation. Problem is, a lot doesn't. I think it's quite easy to
accidentally check something intended as an iterable for emptiness.

Testing a random iterable for emptiness can not be done by testing it's
length.

Quote:
And, as I've explained in other posts, this can lead to subtle bugs.

If you clearly documents what your function expects (ie sequence or
iterable), then I don't see any subtleties involved...

Quote:
Whereas if you check for emptiness using len, it throws an exception
right away, no bugs. It's safer to use len.

It's safer to decide which protocol is expected, ie iterable or
sequence, and then write the code according to this expectation.

Quote:
(Safest of all is not to
check for emptiness at all.)

Unless you clearly expect a sequence and have to branch according to
it's state (ie empty/not empty).

Quote:
2. This logic doesn't work for numpy arrays. In a lot of cases, a
function expecting a list works perfectly fine if you pass it a numpy
arrray. But, if you were to write such a function with "if lst"
instead of "if len(lst)>0", it's guaranteed to fail. The function is
more generic with the len test.

If the function is to work with non-sequence types, write it so it can
work with non-sequence types.

Quote:
it's possible that these types wouldn't even have a boolean
value and any tests for emptiness would have to be explicit.

Yes ? How ? Calling len() on them ?-)
(hint: reread how len() and bool() works wrt/ __len__())


Yes. If the language had been designed such that a list had no
nb_nonzero slot,

[].__nonzero__
Traceback (most recent call last):

File "<stdin>", line 1, in ?
AttributeError: 'list' object has no attribute '__nonzero__'


Quote:
you'd have to check for emptiness with len.

bool(obj) *do* the test on __len__() if __nonzero__() is not implemented.

Quote:
Perhaps
you're missing some of the nuances of English verb tenses (don't feel
too bad, it's hard). I'm not arguing "what is", I'm arguing what
"could have been if circumstances were different". If the language
were designed differently, then the rules would be different.

Totally true - and totally irrelevant IMHO.

--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'onurb@xiludom.gro'.split('@')])"
Back to top
Patrick Maupin
*nix forums beginner


Joined: 23 Jun 2005
Posts: 32

PostPosted: Tue Jul 18, 2006 4:32 pm    Post subject: Re: Coding style Reply with quote

Carl Banks wrote:
Quote:
Here's another reason not to use "if lst". Say you have a function
that looks like this:

def process_values(lst):
if not lst:
return
do_expensive_initialization_step()
for item in lst:
do_something_with(item)
do_expensive_finalization_step()

That works, right? No problem, right?

What if you called the function like this:

process_values(x.strip() for x in values_lst)

Oops, now we've just gone through an expensive initialization and
finalization for nothing (since values_lst was empty). Maybe some
subtle bugs introduced. If we're lucky, the finalization step will
throw an exception.

If we had used "if len(list)>0", we'd have gotten a nice exception
telling us that a generator is not welcome. Then we'd have changed the
argument to a list comprehension, or better, changed the function to
work for any iterator.

The argument that one should always use len() to test whether sequences
are empty or not simply because the use of len() gives a free "is it a
sequence?" type-check is not apt to be well received by an audience
which rejects explicit type-checking in general.

The specific example given, where a lack of a len() works correctly,
except for using more execution time on generators than on lists, is
not apt to be well received by an audience which rejects premature
optimizations in general, and which believes that if you don't notice a
speed problem, it doesn't exist, and if you _do_ notice a speed
problem, the profiler is the best tool to attack it with.

The perverse wish, expressed in the specific example, that SOME piece
of code SOMEWHERE should PLEASE throw an exception because some idiot
passed a generator expression rather than a list into a function, is
not apt to be well received by an audience which strives for generality
when it makes sense; and I daresay most members of that audience, if
confronted with the wished-for exception, would fix the function so
that it quite happily accepted generator expressions, rather than
changing a conditional to use len() just so that an equivalent
exception could happen a bit earlier.

I'm not saying that _everybody_ on this list is in any of these
audiences, but I would suspect that all the people arguing with you are
:)

Regards,
Pat
Back to top
Daniel Dittmar
*nix forums addict


Joined: 28 Feb 2005
Posts: 93

PostPosted: Tue Jul 18, 2006 5:03 pm    Post subject: Re: Coding style Reply with quote

Patrick Maupin wrote:
Quote:
The argument that one should always use len() to test whether sequences
are empty or not simply because the use of len() gives a free "is it a
sequence?" type-check is not apt to be well received by an audience
which rejects explicit type-checking in general.

No explicit type check. More of an implicit behaviour check. OK,
wise guys are not apt to be well received by ... well, any audience.

Quote:
The perverse wish, expressed in the specific example, that SOME piece
of code SOMEWHERE should PLEASE throw an exception because some idiot
passed a generator expression rather than a list into a function, is
not apt to be well received by an audience which strives for generality
when it makes sense; and I daresay most members of that audience, if
confronted with the wished-for exception, would fix the function so
that it quite happily accepted generator expressions, rather than
changing a conditional to use len() just so that an equivalent
exception could happen a bit earlier.

Premature generalization: the new 'premature optimization'.

Daniel
Back to top
Volker Grabsch
*nix forums beginner


Joined: 14 May 2005
Posts: 19

PostPosted: Tue Jul 18, 2006 5:06 pm    Post subject: Re: Coding style Reply with quote

Bruno Desthuilliers <onurb@xiludom.gro> schrieb:
Quote:
Carl Banks wrote:
Bruno Desthuilliers wrote:

I'm well aware of Python's semantics, and it's irrelvant to my
argument.
[...]
If the language
were designed differently, then the rules would be different.

Totally true - and totally irrelevant IMHO.

I strongly advise not to treat each others thoughts as irrelevant.
Assuming the opposite is a base of every public dicussion forum.


I assume here is a flaw in Python. To explain this, I'd like to
make Bruno's point clearer. As usually, code tells more then
thousand words (an vice versa Smile).

Suppose you have two functions which somehow depend on the emptyness
of a sequence. This is a stupid example, but it demonstrates at
least the two proposed programming styles:

------------------------------------------------------
Quote:
def test1(x):
.... if x:

.... print "Non-Empty"
.... else:
.... print "Empty"
....
Quote:
def test2(x):
.... if len(x) > 0:

.... print "Non-Empty"
.... else:
.... print "Empty"
------------------------------------------------------

Bruno pointed out a subtle difference in the behaviour of those
functions:

------------------------------------------------------
Quote:
a = []
test1(a)
Empty
test1(iter(a))
Non-Empty
test2(a)
Empty
test2(iter(a))
Traceback (most recent call last):

File "<stdin>", line 1, in ?
File "<stdin>", line 2, in test2
TypeError: len() of unsized object
------------------------------------------------------


While test1() returns a wrong/random result when called with an
iterator, the test2() function breaks when beeing called wrongly.

So if you accidently call test1() with an iterator, the program
will do something unintended, and the source of that bug will be
hard to find. So Bruno is IMHO right in calling that the source
of a suptle bug.

However, if you call test2() with an iterator, the program will
cleanly break early enough with an exception. That is generally
wanted in Python. You can see this all over the language, e.g.
with dictionaries:

------------------------------------------------------
Quote:
d = { 'one': 1 }
print d['one']
1
print d['two']
Traceback (most recent call last):

File "<stdin>", line 1, in ?
KeyError: 'two'
------------------------------------------------------

Python could have been designed to return None when d['two'] has been
called, as some other (bad) programming languages would. This would
mean that the problem will occur later in the program, making it easy
to produce a subtle bug. It would be some effort to figure out the
real cause, i.e. that d had no entry for 'two'.

Luckily, Python throws an exception (KeyError) just at the original
place where the initial mistake occured. If you *want* to get None in
case of a missing key, you'll have to say this explicitly:

------------------------------------------------------
Quote:
print d.get('two', None)
None

------------------------------------------------------

So maybe "bool()" should also break with an exception if an object
has neither a __nonzero__ nor a __len__ method, instead of defaulting
to True. Or a more strict variant of bool() called nonempty() should
exist.

Iterators don't have a meaningful Boolean representation, because
phrases like "is zero" or "is empty" don't make sense for them. So
instead of answering "false", an iterator should throw an exception
when beeing asked whether he's empty.

If a function expects an object to have a certain protocol (e.g.
sequence), and the given object doesn't support that protocol,
an exception should be raised. This usually happens automatically
when the function calls a non-existing method, and it plays very
well with duck typing.

test2() behaves that way, but test1() doesn't. The reason is a
sluttery of Python. Python should handle that problem as strict
as it handles a missing key in a dictionary. Unfortunately, it
doesn't.

I don't agree with Bruno that it's more natural to write
if len(a) > 0:
...
instead of
if a:
...

But I think that this is a necessary kludge you need to write
clean code. Otherwise you risk to create subtle bugs. This advise,
however, only applies when your function wants a sequence, because
only in that can expect "len(a)" to work.

I also agree with Carl that "if len(a) > 0" is less universal than
"if a", because the latter also works with container-like objects
that have a concept of emptiness, but not of length.

However, this case is less likely to happen than shooting yourself
in the foot by passing accidently an iterator to the function
without getting an exception. I think, this flaw in Python is deep
enough to justify the "len() > 0" kludge.


IMHO, that flaw of Python should be documented in a PEP as it violates
Python's priciple of beeing explicit. It also harms duck typing.


Greets,

Volker

--
Volker Grabsch
---<<(())>>---
Administrator
NotJustHosting GbR
Back to top
Google

Back to top
Display posts from previous:   
Post new topic   Reply to topic Page 3 of 6 [86 Posts] Goto page:  Previous  1, 2, 3, 4, 5, 6 Next
View previous topic :: View next topic
The time now is Fri Jul 30, 2010 2:51 am | All times are GMT
navigation Forum index » Programming » python
Jump to:  

Similar Topics
Topic Author Forum Replies Last Post
No new posts Coding standard Carlos Martinez C++ 7 Wed Jul 19, 2006 11:48 am
No new posts registering class methods as C style callbacks noone@all.com C++ 11 Mon Jul 17, 2006 5:35 pm
No new posts Need Help with a PHP Coding Issue Brent PHP 4 Sun Jul 16, 2006 5:09 pm
No new posts Bug#378289: ITP: sigma-align -- Simple greedy multiple al... Charles Plessy devel 0 Sat Jul 15, 2006 3:00 am
No new posts Version control philosophy and style JDS PHP 4 Fri Jul 14, 2006 7:55 pm

Copyright © 2004-2005 DeniX Solutions SRL   Other DeniX Solutions sites: Unix/Linux blog |  electronics forum |  medicine forum |  science forum |  Privacy Policy



Powered by phpBB © 2001, 2005 phpBB Group
[ Time: 0.1827s ][ Queries: 14 (0.1037s) ][ GZIP on - Debug on ]