Attack a sacred Python Cow

R

Russ P.

Iterators are funny: if there's any reason you should not use "if x"
it's because of them. Built-in iterators are always true, so if
you're writing a function that accepts an iterable you should never
use the "if x" to test whether it's empty, because it fails for a
whole class of iterables.

However, given that that wart exists, your example does work for "if
x" and not with "if len(x)!=0".

Then again, it really only works to accommodate faulty code, because
no code that expects an iterable should be using that test in the
first place. (Unless you wrap every iterable as soon as you get it,
but then you're not bound to use __nonzero__.)

Carl Banks

All this discussion about "if x" has me wondering. I use it all the
time because a fully explicit test just seems redundant. But maybe it
does have some value in terms of readability and type checking. After
all, it is possible to forget whether something is a number or a list.

Having said that, it would sure be nice to be able to write

if myList is not empty:

instead of

if len(myList) != 0:
 
C

Carl Banks

The no-advance filters have to return the object because I don't just
forget about it; I evaluate whether I pass it to the next filter or drop
it in a completely different queue for use in the next stage of the
operation. True means 'I'm ready to move on to the next stage,' False
means 'Do the filter thing some more.'

I think I see what you're saying, and yeah I guess that could really
take advantage of polymorphism between very different types.
Furthermore, the argument that I should just change my API to make a
'simple test' work is not very convincing.

I wasn't suggesting you change it: I was trying to ascertain whether
it would have suffered much if you had written it with explicit tests
in the first place, or if Python didn't even have magical booleans.
The natural, obvious way for
a filter to work is to pass through the data it operates on; why on
Earth would it return None? I want to DO something with the data. In
this case, make a decision about where to pass the data next.

If you don't mind me asking: what do you do actually DO with a zero or
empty list?
In Java,
to accomplish this I would have to do lots of introspection and value
checking (adding more any time I came up with a new kind of input), or
make a new kind of interface that gives me a method so I can do a
'simple test' (including wrappers for ints and arrays and anything else
I decide to pass in down the road). But Python supports duck typing and
gives me a handy __nonzero__ method; I can rebind __nonzero__ in my
filters for my own classes, and ints and lists are handled how I want
them to be by default. So why jump through hoops instead of just using
'if x'?

Ah, so it's just happens to work. Still, just happening to work
works. (shrug)
I don't have any postable code (it's in a half way state and I haven't
touched it for a while), but I'll see if I can't find the time to bang
something up to give you the gist.

I wouldn't bother at this point. I was looking to see if someone
could come up with something to disprove my belief on the polymorphic
uselessness of "if x" relative to explicit tests, and if (as I
anticipated) they did not, I could claim that "if x" is really just a
glorified keystroke saver. But I now realize that the failure of this
bunch doesn't prove anything. I don't think most people even realize
why answering the question I asked would demonstrate the usefulness of
"if x".

Your example isn't exactly the smoking gun I was looking for, but I
guess we'll have to admit that at least one usage will suffer for not
having it.


Carl Banks
 
C

Carl Banks

All this discussion about "if x" has me wondering. I use it all the
time because a fully explicit test just seems redundant. But maybe it
does have some value in terms of readability and type checking. After
all, it is possible to forget whether something is a number or a list.

IMO, the only time I think "if x" is really dangerous is if you are
using "if x" instead of "if x is None" to distinguish between None and
a type that can have false values. Well, also it can backfire to use
"if x" to check whether an iterable is empty since you can get a false
positive if it's an iterator.

Other than that it's maybe slighly less type safe to use explicit
test.

Having said that, it would sure be nice to be able to write

if myList is not empty:

instead of

if len(myList) != 0:

I can agree with this.


Carl Banks
 
R

Russ P.

I can agree with this.

But I guess that could only work if there were only one empty list
that represents all empty lists (as there is only one actual "None").
I don't know if that makes sense or not.
 
R

Russ P.

I'm getting this sneaking suspicion that you guys are all putting us on.

As I said in an earlier post, I realize that this would only work if
there were only one copy of "empty" (as there is only one copy of
"None"). I don't know off hand if that is feasible or not.

You reply reeks of the kind of pedantic snobbishness that makes me
sick.
 
R

Russ P.

It really doesn't, since it presumably wouldn't apply to just list
types. There are plenty of other sequence types: such as tuples,
strings, or even arbitrary custom types. Emptiness is a test for the
value of an object, not a test for whether it is identical to another
object, so this is a very misleading of the `is` operator, bordering on
abuse.

This syntax would make far less sense than the existing Boolean test.

--
Erik Max Francis && (e-mail address removed) &&http://www.alcyone.com/max/
San Jose, CA, USA && 37 18 N 121 57 W && AIM, Y!M erikmaxfrancis
The doors of Heaven and Hell are adjacent and identical.
-- Nikos Kazantzakis

Now that's more reasonable. Note that I said, "it would be nice to be
able to write," not "this is how it should be done."

Come to think of it, shouldn't the list type have an "isempty" method?
Or does it?
 
R

Russ P.

It's only feasible if you change what `is` means for this one bizarre
use case, which isn't a good idea.


Well, if understanding what the `is` operator means is pedantic
snobbishness, then hey, go right ahead.

--
Erik Max Francis && (e-mail address removed) &&http://www.alcyone.com/max/
San Jose, CA, USA && 37 18 N 121 57 W && AIM, Y!M erikmaxfrancis
The doors of Heaven and Hell are adjacent and identical.
-- Nikos Kazantzakis

I fully understand what the "is" operator is, and I never had any
problem with it at all, thank you.

But then again, I suppose that depends on what the meaning of "is"
is ...
 
R

Russ P.

Yes. It's written:

if not aList:
...

As you know, that is not quite exactly the same thing. An "isempty"
method would fail if aList were an integer, and such failure might be
desirable if someone mistakenly had aList pointing to an integer.
 
C

Carl Banks

Perhaps in the particular use case you're thinking of (numeric types vs.
container types), there aren't any good examples. But who cares?

You don't have to. I am trying to set the record straight on just how
much polymophism "if x" supports relative to explicit tests, which is
to say, not much.

BTW, I haven't changed my criteria since I asked for the challenge.


Carl Banks
 
C

Carl Banks

But I guess that could only work if there were only one empty list
that represents all empty lists (as there is only one actual "None").
I don't know if that makes sense or not.

I mean in general. I wouldn't spell it like that. I would prefer if
empty(x), with an __empty__ method. (And support __nonzero__ aka
__bool__ dropped completely.)


Carl Banks
 
H

Heiko Wundram

Am Mittwoch, 30. Juli 2008 08:30:48 schrieb Russ P.:
As I said in an earlier post, I realize that this would only work if
there were only one copy of "empty" (as there is only one copy of
"None"). I don't know off hand if that is feasible or not.

You reply reeks of the kind of pedantic snobbishness that makes me
sick.

I can understand (and pretty much sympathise) that you get this kind of reply,
simply because the point you and Carl Banks (formulated somewhat differently)
put up has been answered again and again (in this thread), and I can only
repeat it once more:

__nonzero__(), i.e. the "cast" to boolean, is THE WAY to test whether a
container is empty or not. Like this design decision, or don't like it, but
the discussion is not going to go anywhere unless you concede that there is a
(very explicit!) way to test for non-emptiness of a container already, and
you're currently simply discussing about adding/using syntactic sugar
(different means of expressing the test) to suit your own personal taste
better. Anyway, check the documentation for __nonzero__(): if the object
doesn't implement that, but implements __len__(), the interpreter "replaces"
the __nonzero__() test by __len__()>0, so I guess someone in the design
department must've seen it logical for the truth value of a container to
express the test "len(x)>0" at some point in time to make this interpretation
for the truth value of a container.

There cannot be an argument about missing/misplaced functionality (that's what
you make it sound like), if the functionality for doing what you want to do
is there and you simply don't like the syntax, which I can somewhat relate to
because style is a personal thing, even though I don't see either points made
by you or Carl Banks, because implicit casting to bool is so common in pretty
much every programming language to test for "truth" of an object, and IMHO
it's completely logical to extend that idea to containers to mean
empty/non-empty.

Eric Max Francis tried to explain why your syntactic "enhancement" would come
at a much greater price than its worth, and he's absolutely right in that, as
it's an abuse of the "is" operator, but again, that's a somewhat different
point. It changes nothing about the fact that all this discussion centers
around something that is a non-point, but simply a matter of personal taste.
 
R

Russ P.

Am Mittwoch, 30. Juli 2008 08:30:48 schrieb Russ P.:




I can understand (and pretty much sympathise) that you get this kind of reply,
simply because the point you and Carl Banks (formulated somewhat differently)
put up has been answered again and again (in this thread), and I can only
repeat it once more:

__nonzero__(), i.e. the "cast" to boolean, is THE WAY to test whether a
container is empty or not. Like this design decision, or don't like it, but
the discussion is not going to go anywhere unless you concede that there is a
(very explicit!) way to test for non-emptiness of a container already, and
you're currently simply discussing about adding/using syntactic sugar
(different means of expressing the test) to suit your own personal taste
better. Anyway, check the documentation for __nonzero__(): if the object
doesn't implement that, but implements __len__(), the interpreter "replaces"
the __nonzero__() test by __len__()>0, so I guess someone in the design
department must've seen it logical for the truth value of a container to
express the test "len(x)>0" at some point in time to make this interpretation
for the truth value of a container.

There cannot be an argument about missing/misplaced functionality (that's what
you make it sound like), if the functionality for doing what you want to do
is there and you simply don't like the syntax, which I can somewhat relate to
because style is a personal thing, even though I don't see either points made
by you or Carl Banks, because implicit casting to bool is so common in pretty
much every programming language to test for "truth" of an object, and IMHO
it's completely logical to extend that idea to containers to mean
empty/non-empty.

Eric Max Francis tried to explain why your syntactic "enhancement" would come
at a much greater price than its worth, and he's absolutely right in that, as
it's an abuse of the "is" operator, but again, that's a somewhat different
point. It changes nothing about the fact that all this discussion centers
around something that is a non-point, but simply a matter of personal taste.

Oh, Lordy. I understand perfectly well how boolean tests, __len__, and
__nonzero__ work in Python. It's very basic stuff. You can quit
patronizing me (and Carl too, I'm sure).

The point that you seem to be missing, or refuse to acknowledge for
some reason, is that "if x" can be mistakenly applied to any object
when the programmer thinks that x is a list -- and the programmer will
receive no feedback on the error.

I have made errors like that, and I could have saved some time had I
used an "empty" method that only applies to a list or other sequence.

Is that an important issue? I don't know. I'm not claiming it is. But
you cannot just sweep it away as nothing.
 
H

Heiko Wundram

Am Mittwoch, 30. Juli 2008 09:18:48 schrieb Russ P.:
Oh, Lordy. I understand perfectly well how boolean tests, __len__, and
__nonzero__ work in Python. It's very basic stuff. You can quit
patronizing me (and Carl too, I'm sure).

I'll stop repeating what the current state is (which might sound like I'm
patronizing, but that's not the real intent actually, I'm just trying to get
the discussion straight with what is fact, namely that there already exists
an explicit way which doesn't seem to be recognized by some people here) if
you agree to my point that we're not talking about a problem with Python, but
about a personal stylistic issue with the language design. That's just what I
said in my last mail: I can concede that you, personally, have an issue with
the current state, but for me and seemingly also for a majority of people who
have posted in this thread, that's a non-issue.
The point that you seem to be missing, or refuse to acknowledge for
some reason, is that "if x" can be mistakenly applied to any object
when the programmer thinks that x is a list -- and the programmer will
receive no feedback on the error.

I have made errors like that, and I could have saved some time had I
used an "empty" method that only applies to a list or other sequence.

For me, I've never had this kind of problem, simply because if I test for the
truth value of something, I'm going to do something with it later on, and as
soon as I'm doing something with it, I'll see whether the object supports the
interface I want it to support (and get an error there if the object doesn't
support the basic notions of a sequence type, for example, i.e. __iter__()).
Testing for truth is IMHO not doing something with an object, and as such I'm
more than happy that it's "foolproof". This is one thing that I personally
find attractive about Python's way of duck-typing.

But, if you personally have been bitten by this, give an example, and I'm sure
that we can start discussing from there. I've already given an example why
the explicit test for length is less polymorphic than the explicit test for
truth of a container elsewhere as a proof for the point I'm trying to make.
 
R

Russ P.

Am Mittwoch, 30. Juli 2008 09:18:48 schrieb Russ P.:


I'll stop repeating what the current state is (which might sound like I'm
patronizing, but that's not the real intent actually, I'm just trying to get
the discussion straight with what is fact, namely that there already exists
an explicit way which doesn't seem to be recognized by some people here) if
you agree to my point that we're not talking about a problem with Python, but
about a personal stylistic issue with the language design. That's just what I
said in my last mail: I can concede that you, personally, have an issue with
the current state, but for me and seemingly also for a majority of people who
have posted in this thread, that's a non-issue.



For me, I've never had this kind of problem, simply because if I test for the
truth value of something, I'm going to do something with it later on, and as
soon as I'm doing something with it, I'll see whether the object supports the
interface I want it to support (and get an error there if the object doesn't
support the basic notions of a sequence type, for example, i.e. __iter__()).
Testing for truth is IMHO not doing something with an object, and as such I'm
more than happy that it's "foolproof". This is one thing that I personally
find attractive about Python's way of duck-typing.

But, if you personally have been bitten by this, give an example, and I'm sure
that we can start discussing from there. I've already given an example why
the explicit test for length is less polymorphic than the explicit test for
truth of a container elsewhere as a proof for the point I'm trying to make.

Fair enough. I have no dog in this particular fight. I just think it
wouldn't hurt to add an "isempty()" or "isnonempty()" method to the
list type, and let people use it if they wish, or continue using "if
x" if that's what they prefer.
 
E

Ethan Furman

Carl said:
I wouldn't bother at this point. I was looking to see if someone
could come up with something to disprove my belief on the polymorphic
uselessness of "if x" relative to explicit tests, and if (as I
anticipated) they did not, I could claim that "if x" is really just a
glorified keystroke saver. But I now realize that the failure of this
bunch doesn't prove anything. I don't think most people even realize
why answering the question I asked would demonstrate the usefulness of
"if x".

Your example isn't exactly the smoking gun I was looking for, but I
guess we'll have to admit that at least one usage will suffer for not
having it.

Carl Banks

Even for those that did realize, and in fact hoped that that is what you
were attempting to accomplish, it was still quite frustrating to see you
ignoring all the non-code, yet perfectly valid examples of why "if x"
was not only valid, but the most pythonic[1] way to get the task done.
I think it would have been a better discussion if you had responded with
reasons why, and not just parroted the "show me the code!" line over and
over and over and ... It seemed as if you thought you were the
professor, impatiently trying to teach a class full of idiots by playing
the devil's advocate. I was sure hoping someone would get the actual
code example and post it, partly because I enjoy learning, but mostly
because it would (hopefully) shut you up and move the conversation
along. In fact, somebody did post some code about a custom matrix
class, where __len__ was useless, and still you kept on with... pah.
It's late, so before I say something stupid I'll finish this. My last
thought on the matter -- up until this thread I had looked forward to
your posts, Carl. I think you did more damage than good to yourself
with this stunt.
~Ethan~

[1] by pythonic I mean using the features of the language that make
sense. In this case, the __nonzero__ function to have the object in
question tell us whether or not it's empty. This seems so basic (the
__nonzero__ function, that is, and its purpose) -- do you really need
code to prove it to yourself?
 
M

Maric Michaud

Le Tuesday 29 July 2008 23:48:31 (e-mail address removed), vous avez écrit :
Here's a function, print_members.  It's just something that takes some
iterable and prints its members in XML.  It's special-cased so that an
empty iterable gets an empty tag.  (This is a bit of a trivial
example, I admit; the point is that the empty iterable is a special
case.)

def print_members(iterable):
    if not iterable:
        print '<members />'
        return
    print '<members>'
    for item in iterable:
        print '<item>%s</item>' % item
    print '</members>'

...
So print_members can work on iterables that have no len(), and handle
the special case of an empty iterable, as long as __nonzero__ is
implemented.

But iterables can have no notion of emptiness too :
[25]: print_members((e for e in range(0)))
<members>
</members>

Your function is just wrong assuming that, it should be written :
[31]: def print_members(iterable):
print '<members',
empty = True
for item in iterable:
if empty :
empty = False
print '>'
print '<item>%s</item>' % item
print empty and '/>' or '</members>'
....:
....:
[40]: print_members((e for e in range(0)))
[41]: print_members((e for e in range(1)))
<members >
<item>0</item>
</members>


Counterexample:

While "if x" works well in some circumstances, I don't like using it
for purely numeric types.  For instance, I have a mutable Signal class
for doing some basic DSP.  Among other things, I can apply a DC offset
to the signal (it just adds the offset to all the samples).  I have a
special case for an offset of 0 so I don't have to loop through all
the samples (I also have a two-pass remove_offset method that
subtracts the average; if it's already properly centred, I can skip a
step).

class Signal:
    [...]
    def dc_offset(self, amount):
        if amount == 0:
            return
        self.samples = [sample + amount for sample in self.samples]

This function is also wrong assuming that because amount compare to zero, it
can be added to sample.

If you want to make type checking just check the type or convert your
parameter to an int, but the test "== 0" is of no help here.

The only valuable point I see for this idiom is to make more explicit I am
testing a numerical value.
But your example is a good objection to this, with well chosen name, ie.
amount, it's quite clear "if not amount :" is testing the zero value of a
numerical value.
 
E

Ethan Furman

Russ said:
Oh, Lordy. I understand perfectly well how boolean tests, __len__, and
__nonzero__ work in Python. It's very basic stuff. You can quit
patronizing me (and Carl too, I'm sure).

The point that you seem to be missing, or refuse to acknowledge for
some reason, is that "if x" can be mistakenly applied to any object
when the programmer thinks that x is a list -- and the programmer will
receive no feedback on the error.

You know... or maybe you don't, since you did just say what you just
said... that is such a ridiculous point it only barely qualifies as
deserving comment. Rather than be really rude, I'll just say: test
it's type() if the function is that specific, or your code that brittle.
Python is not there to catch your logic mistakes, that's up to you.
I have made errors like that, and I could have saved some time had I
used an "empty" method that only applies to a list or other sequence.

Is that an important issue? I don't know. I'm not claiming it is. But
you cannot just sweep it away as nothing.

I don't sweep it away as nothing -- I sweep it away as stupid. The
programmer is responsible for his (or her) program. An analogy would be
a driver and a car -- if the driver cannot handle the power and speed of
a fancy car (python :), then the driver should get a different car
better matched to his abilities. It's not up to the car to say "oh, the
speed limit is 50 here, I better apply the brakes for the driver."

~Ethan~
 
G

giltay

Le Tuesday 29 July 2008 23:48:31 (e-mail address removed), vous avez écrit :
def print_members(iterable):
    if not iterable:
        print '<members />'
        return
    print '<members>'
    for item in iterable:
        print '<item>%s</item>' % item
    print '</members>'

But iterables can have no notion of emptiness too :
[25]: print_members((e for e in range(0)))

<members>
</members>

Ack! Maybe I meant "container" rather than "iterable". Or maybe I'd
be wrong on that count, too. Other people have come up with better
examples, so I won't try to fix my hasty code (although I'll keep that
in mind if I have to write a custom XML writer).
class Signal:
    [...]
    def dc_offset(self, amount):
        if amount == 0:
            return
        self.samples = [sample + amount for sample in self.samples]

This function is also wrong assuming that because amount compare to zero, it
can be added to sample.

Not quite. I'm assuming that if amount equals 0, then amount is some
scalar. In fact, only if that comparison fails will I get my
exception: since [] != 0, it will then try to add sample + [], which
will raise TypeError.
If you want to make type checking just check the type or convert your
parameter to an int, but the test "== 0" is of no help here.

I'm not going for type checking here because I want Signal to support
int and float samples (and numpy.int16, &c.).
The only valuable point I see for this idiom is to make more explicit I am
testing a numerical value.

That's one of the reasons I wrote it that way. Signal has other
methods that take lists (like mix and envelope), which I could get
confused with the ones that take scalars (offset and change volume).

Cheers,
Geoff G-T
 
H

Hyuga

Fair enough. I have no dog in this particular fight. I just think it
wouldn't hurt to add an "isempty()" or "isnonempty()" method to the
list type, and let people use it if they wish, or continue using "if
x" if that's what they prefer.

Go right on ahead. You could implement it like this:

class superenhancedlist(list):
def isempty(self):
return not self
False

Amazingly useful! Go ahead and use that in all your code. Anyone
else who comes along and looks at it or tries to maintain it will
really love you for it.
 
M

Maric Michaud

Le Wednesday 30 July 2008 15:31:28 (e-mail address removed), vous avez écrit :
class Signal:
    [...]
    def dc_offset(self, amount):
        if amount == 0:
            return
        self.samples = [sample + amount for sample in self.samples]

This function is also wrong assuming that because amount compare to zero,
it can be added to sample.

Not quite.  I'm assuming that if amount equals 0, then amount is some
scalar.  In fact, only if that comparison fails will I get my
exception: since [] != 0, it will then try to add sample + [], which
will raise TypeError.
If you want to make type checking just check the type or convert your
parameter to an int, but the test "== 0" is of no help here.

I'm not going for type checking here because I want Signal to support
int and float samples (and numpy.int16, &c.).

Ok, but the fact that amount == 0 passes, doesn't ensure you didn't a
programming error, this add just some relative robustness (protect you from
passing an empty list). And a reader would probably not see your intention
here (he already expect a scalar due to the name of the variable).

This is exactly the problem ABC is intended to solve.

Without ABC, to explicitly ensure amount is a scalar, just doing a int(amount)
or int(abs(amount)) if you want to deal with complex numbers too, at the
begining of the function is a common idiom.
 

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,769
Messages
2,569,582
Members
45,059
Latest member
cryptoseoagencies

Latest Threads

Top