473,441 Members | 1,972 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,441 software developers and data experts.

Attack a sacred Python Cow

Hi everyone,

I'm a big Python fan who used to be involved semi regularly in
comp.lang.python (lots of lurking, occasional posting) but kind of
trailed off a bit. I just wrote a frustration inspired rant on my
blog, and I thought it was relevant enough as a wider issue to the
Python community to post here for your discussion and consideration.

This is not flamebait. I love Python, and I'm not out to antagonise
the community. I also realise that one of the issues I raise is way
too ingrained to be changed now. I'd just like to share my thinking on
a misstep in Python's guiding principles that has done more harm than
good IMO. So anyway, here's the post.

I've become utterly convinced that at least one criticism leveled at
my favourite overall programming language, Python, is utterly true and
fair. After quite a while away from writing Python code, I started
last night on a whim to knock up some code for a prototype of an idea
I once had. It's going swimmingly; the Python Image Library, which I'd
never used before, seems quick, intuitive, and with the all the
features I need for this project. As for Python itself, well, my heart
still belongs to whitespace delimitation. All the basics of Python
coding are there in my mind like I never stopped using them, or like
I've been programming in this language for 10 years.

Except when it comes to Classes. I added some classes to code that had
previously just been functions, and you know what I did - or rather,
forgot to do? Put in the 'self'. In front of some of the variable
accesses, but more noticably, at the start of *every single method
argument list.* This cannot be any longer blamed as a hangover from
Java - I've written a ton more code, more recently in Python than in
Java or any other OO language. What's more, every time I go back to
Python after a break of more than about a week or so, I start making
this 'mistake' again. The perennial justification for this 'feature'
of the language? That old Python favourite, "Explicit is better than
implicit."

I'm sorry, but EXPLICIT IS NOT NECESSARILY BETTER THAN IMPLICIT.
Assembler is explicit FFS. Intuitive, clever, dependable, expected,
well-designed *implicit* behaviour is one of the chief reasons why I
use a high level language. Implicitly garbage collect old objects for
me? Yes, please!

I was once bitten by a Python wart I felt was bad enough to raise and
spend some effort advocating change for on comp.lang.python (never got
around to doing a PEP; partly laziness, partly young and inexperienced
enough to be intimidated at the thought. Still am, perhaps.)

The following doesn't work as any sane, reasonable person would
expect:

# Blog code, not tested
class A():
def __eq__(self, obj):
return True
a = A()
b = []
assert a == b
assert not (a != b)

The second assertion fails. Why? Because coding __eq__, the most
obvious way to make a class have equality based comparisons, buys you
nothing from the != operator. != isn't (by default) a synonym for the
negation of == (unlike in, say, every other language ever); not only
will Python let you make them mean different things, without
documenting this fact - it actively encourages you to do so.

There were a disturbingly high number of people defending this
(including one quite renowned Pythonista, think it might have been
Effbot). Some had the temerity to fall back on "Explicit is better
than implict: if you want != to work, you should damn well code
__ne__!"

Why, for heaven's sake, should I have to, when in 99.99% of use cases
(and of those 0.01% instances quoted in the argument at the time only
one struck me as remotely compelling) every programmer is going to
want __ne__ to be the logical negation of __eq__? Why, dear Python,
are you making me write evil Java-style language power reducing
boilerplate to do the thing you should be doing yourself anyway?
What's more, every programmer is going to unconciously expect it to
work this way, and be as utterly as mystified as me when it fails to
do so. Don't tell me to RTFM and don't tell me to be explicit. I'll
repeat myself - if I wanted to be explicit, I'd be using C and
managing my own memory thank you very much. Better yet, I'd explicitly
and graphically swear - swear in frustration at this entrenched design
philosophy madness that afflicts my favourite language.

I think the real problem with the explicit is better than implicit,
though, is that while you can see the underlying truth its trying to
get at (which is perhaps better expressed by Ruby's more equivocal,
less dependable, but more useful Principle of Least Surprise), in its
stated form its actually kind of meanginless and is used mainly in
defence of warts - no, we'll call them for what they are, a language
design *bugs*.

You see, the problem is, there's no such thing of explict in
programming. Its not a question of not doing things implicitly; its a
question of doing the most sensible thing implicitly. For example this
python code:

some_obj.some_meth(some_arg1, some_arg2)

is implicitly equivalent to

SomeClass.some_meth(some_obj, some_arg1, some_arg2)

which in turn gives us self as a reference to some_obj, and Python's
OO model merrily pretends its the same as Java's when in fact is a
smarter version that just superficially looks the same.

The problem is that the explicit requirement to have self at the start
of every method is something that should be shipped off to the
implicit category. You should have to be explicit, yes - explicit when
you want the *other* behaviour, of self *not* being an argument,
because thats the more unusual, less likely case.

Likewise,

a != b

is implicitly equivalent to something like calling this function (may
not be correct, its a while since I was heavily involved in this
issue):

def equal(a, b):
if hasattr(a, "__ne__"): return a.__ne__(b)
if hasattr(b, "__ne__"): return b.__ne__(a)
if hasattr(a, "__cmp__"): return not (a.__cmp__(b) == 0)
if hasattr(b, "__cmp__"): return not (b.__cmp__(a) == 0)
return not (a is b)

There's absolutely nothing explicit about this. I wasn't arguing for
making behaviour implicit; I was arguing for changing the stupid
implict behaviour to something more sensible and less surprising.

The sad thing is there are plenty of smart Python programmers who will
justify all kinds of idiocy in the name of their holy crusade against
the implict.

If there was one change I could make to Python, it would be to get
that damn line out of the Zen.
Jul 24 '08
270 7857
On Jul 30, 2:06 am, Erik Max Francis <m...@alcyone.comwrote:
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
Jul 30 '08 #201
On Jul 30, 1:58 am, "Russ P." <Russ.Paie...@gmail.comwrote:
On Jul 29, 10:33 pm, Carl Banks <pavlovevide...@gmail.comwrote:
On Jul 30, 1:15 am, "Russ P." <Russ.Paie...@gmail.comwrote:
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.

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
Jul 30 '08 #202
Am Mittwoch, 30. Juli 2008 08:30:48 schrieb Russ P.:
On Jul 29, 11:09 pm, Erik Max Francis <m...@alcyone.comwrote:
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.
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.

--
Heiko Wundram
Jul 30 '08 #203
On Jul 30, 12:03 am, Heiko Wundram <modeln...@modelnine.orgwrote:
Am Mittwoch, 30. Juli 2008 08:30:48 schrieb Russ P.:
On Jul 29, 11:09 pm, Erik Max Francis <m...@alcyone.comwrote:
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.

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.

--
Heiko Wundram
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.
Jul 30 '08 #204
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.

--
Heiko Wundram
Jul 30 '08 #205
On Jul 30, 12:49 am, Heiko Wundram <modeln...@modelnine.orgwrote:
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.

--
Heiko Wundram
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.
Jul 30 '08 #206
Russ P. wrote:
On Jul 29, 11:36 pm, Erik Max Francis <m...@alcyone.comwrote:
>Russ P. wrote:
>>Come to think of it, shouldn't the list type have an "isempty" method?
Or does it?
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.
If you're that concerned about what the type is, then you can do
explicit typechecks. Those are discouraged precisely because of
Python's dynamism. But knock yourself out.

--
Erik Max Francis && ma*@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 18 N 121 57 W && AIM, Y!M erikmaxfrancis
The actor is not quite a human being -- but then, who is?
-- George Sanders
Jul 30 '08 #207
Carl Banks wrote:
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.)
So your argument is purely about style, then. You just wish it were
written differently.

--
Erik Max Francis && ma*@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 18 N 121 57 W && AIM, Y!M erikmaxfrancis
The actor is not quite a human being -- but then, who is?
-- George Sanders
Jul 30 '08 #208
Russ P. wrote:
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).
You suggested a syntax for testing non-emptiness (`x is not empty`)
which indicated a profound misunderstanding of what the `is` operator does.

You then acknowledged that there might be a problem because of the
implication if the `is` operator and weren't sure whether it would work
or not:

| 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.

This ends with you still sounding confused about what the operator does,
because that can't make sense if you take into account the meaning of
the `is` operator (surely not all empty lists are the same object) and
polymorphism (not all empty containers are empty lists).

Hey, everybody goofs. But pointing figures here doesn't help, since
it's not unreasonable to assume that someone who says something clearly
misunderstanding a feature of the language, and followups to responses
_continuing to be confused about it_, is, in fact, confused. The only
reason anyone thought you were confused was by your bizarre suggestion
about the `empty` syntax and then your confused responses afterwards.

Maybe chalk it up to experience and move on?
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.
Well, that's what you get when you use a dynamic language. There are
times when `x + y` doesn't mean numeric addition, or in fact anything
like it. Or `x % y` where it _really_ doesn't mean anything like the
modulus operator. In dynamic languages, the effect of operations depend
on their types. There's really no way around that, and Boolean testing
if an object as in `if x: ...` is no different. It means different
things depending on what `x` is.

--
Erik Max Francis && ma*@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 18 N 121 57 W && AIM, Y!M erikmaxfrancis
The actor is not quite a human being -- but then, who is?
-- George Sanders
Jul 30 '08 #209
Russ P. wrote:
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~
Jul 30 '08 #210
Le Tuesday 29 July 2008 23:48:31 gi****@gmail.com, 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)))
<members />
>>>[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.

--
_____________

Maric Michaud
Jul 30 '08 #211
On Jul 30, 5:09*am, Maric Michaud <ma...@aristote.infowrote:
Le Tuesday 29 July 2008 23:48:31 gil...@gmail.com, 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
Jul 30 '08 #212
Le Wednesday 30 July 2008 15:31:28 gi****@gmail.com, 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.

--
_____________

Maric Michaud
Jul 30 '08 #213


Carl Banks wrote:
That's not what I was asking for. I was asking for a use case for "if
x" that can't be replaced by a simple explicit test. Your example
didn't satisfy that.
But I believe my example of an iterator with __bool__ but not with
__len__ does.

Jul 30 '08 #214
Carl Banks wrote:
On Jul 30, 1:58 am, "Russ P." <Russ.Paie...@gmail.comwrote:
>On Jul 29, 10:33 pm, Carl Banks <pavlovevide...@gmail.comwrote:
>>On Jul 30, 1:15 am, "Russ P." <Russ.Paie...@gmail.comwrote:
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.
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
--
http://mail.python.org/mailman/listinfo/python-list
__nonzero__ is not only meaningful for sequence types.

-Matt
Jul 30 '08 #215
Russ P. wrote:
On Jul 30, 12:03 am, Heiko Wundram <modeln...@modelnine.orgwrote:
>Am Mittwoch, 30. Juli 2008 08:30:48 schrieb Russ P.:
>>On Jul 29, 11:09 pm, Erik Max Francis <m...@alcyone.comwrote:
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.
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.

--
Heiko Wundram

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.
--
http://mail.python.org/mailman/listinfo/python-list
See, I can agree with this. If you're expecting a list (and only a list)
then your point makes sense. 'if x' can get you into trouble if you
_don't_ want its polymorphism.

Although, if my function is expecting a list, my preference is to do:

if not isinstance(x, list):
raise SomeMeaningfulException()
# do stuff with the list

I put my type checking at the top of the function, so readers can
reference it easily.

However, Carl's point is that 'if x' is never preferable to the more
verbose and slower "simple test". I do not agree with this.

-Matt
Jul 30 '08 #216
Carl Banks wrote:
On Jul 29, 6:42 pm, Matthew Fitzgibbons <eles...@nienna.orgwrote:
>Carl Banks wrote:
>>Much like in Steven D'Aprano's example, still the only actual code
snippet I've seen, it seems that this can easily be done with a simple
explicit test by having all no-advance filters return None and testing
with "if x is not None". So it doesn't pass my criterion of being not
replaceable with simple explicit test.
Maybe that's not workable for some reason. Perhaps if you'd post a
code example that shows this, rather than just talking about it, you
might be more persuasive.
Carl Banks
--
http://mail.python.org/mailman/listinfo/python-list
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.
Yes it would have suffered. I chose the implementation I did because it
made the most sense to me and was the most flexible (a key requirement).
Instead of cobbling together my own way, I used the way that Python gave me.

Python doesn't have magic booleans. They are instead a very well-defined
language mechanism that isn't perfect for every circumstance, but is
pretty good for the most part. I wanted to do meaningful boolean tests
on various objects, so I used the mechanism that my language gave me.
>
>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?
Depends on exactly what the next stage is. Typically, zeros and empty
lists are not meaningful for the next stage, so they get dropped then if
they make it through. I don't want to restrict what gets passed through,
though, because I could end up with several meaningful data types,
making a simple test again impossible. So I pass everything through and
let the next stage decide.
>
>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)
Nonono. The point you seem to be missing is that 'if x' is very well
defined. There is nothing magic or arbitrary about what it does. It
works here and elsewhere because Python (a) chooses good default
behavior (its treatment of lists and ints, etc) and (b) gives you a way,
__nonzero__, to change the behavior to suit your needs.
>
>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".
Of course you don't _need_ to have 'if x'; after all, <sarcasm>REAL
programmers code in machine language</sarcasm>. The whole point of a
high-level language is to make life easier. Python is very dynamic and
allows duck typing so that you can use these tools to do clever things
that would otherwise be very difficult. It even gives you a handy
polymorphic mechanism to do boolean tests, which my example illustrates.

You asked for a use case for a polymorphic 'if x' that can't be easily
replaced by a simple test. I gave one. Then you asked for a code sample,
but now have dismissed my sample as not compelling without having seen
it. But here it is anyway (attached). It's pretty rough since I just
threw it together. I'm sure there are mistakes. I also dropped the DAG,
where all the queueing and decision making is handled in the actual
program. The filters and data are arbitrary but should illustrate the
setup. You care about line 66. Again, the same thing could be
accomplished in various ways; but keep in mind that data could be
_anything_, so you can't easily rewrite line 66.
>
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
--
http://mail.python.org/mailman/listinfo/python-list
So you hypothesized that you can easily rewrite any 'if x' as a simple,
explicit test. I produced an example that shows this cannot be done;
therefore your hypothesis is not correct.

For most cases, you can come up with a simple test, even if it's not the
best way to implement you problem. But other times, the poylmorphic,
duck typing behavior of 'if x' allows you to make your problem much
easier, in a way a simple test can't. To deny this fact is to deny to
power of dynamic languages in general.

-Matt

Jul 30 '08 #217
Carl Banks wrote:
On Jul 29, 6:42 pm, Matthew Fitzgibbons <eles...@nienna.orgwrote:
>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
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?
Jul 30 '08 #218
Terry Reedy <tj*****@udel.eduwrote:
>Carl Banks wrote:
>That's not what I was asking for. I was asking for a use case for "if
x" that can't be replaced by a simple explicit test. Your example
didn't satisfy that.
But I believe my example of an iterator with __bool__ but not with
__len__ does.
On the other hand, iterators provide a clear example of problems with "if x":
__nonzero__ for iterators (in general) returns True even if they are 'empty'.

For example, this function (which attempts to avoid making an expensive
call when not necessary) is buggy, but easy to write if you've been
taught that "if x" will work with any kind of object.

def frob(widgets, power):
if widgets:
frobber = Frobber(power) # expensive call
for widget in widgets:
frobber.frob(widget)

-M-
Jul 30 '08 #219
On Jul 30, 1:07 am, Erik Max Francis <m...@alcyone.comwrote:
Russ P. wrote:
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).

You suggested a syntax for testing non-emptiness (`x is not empty`)
which indicated a profound misunderstanding of what the `is` operator does.

You then acknowledged that there might be a problem because of the
implication if the `is` operator and weren't sure whether it would work
or not:
Oh, my. I wrote something like, "It would sure be nice to be able to
write

if x is not empty:

because it reads like natural language. Immediately after I posted it,
I thought, "oh, I'll bet some idiot takes that as a serious proposal."
Sure enough, some idiot did just that almost immediately. And he is
still patronizing me for it.

Hey, dude, if you think I ever had any doubt about what "is" means in
Python, you are simply wrong. Completely wrong. Can you get that
through your thick skull?

One of the problems with this site is that you have pedants who like
to show off their knowledge of the Python language. I suspect that
many of these people know little more than the rules of programming in
Python. They are like someone who thinks he is a writer because he
knows how to use Microsoft Word, or someone who thinks he is a chess
expert because he knows the rules for moving the pieces.
Jul 30 '08 #220
On Jul 30, 11:07 am, Terry Reedy <tjre...@udel.eduwrote:
Carl Banks wrote:
That's not what I was asking for. I was asking for a use case for "if
x" that can't be replaced by a simple explicit test. Your example
didn't satisfy that.

But I believe my example of an iterator with __bool__ but not with
__len__ does.
And I believe I followed up to your post saying as much. :)
Carl Banks
Jul 31 '08 #221
On Jul 30, 3:56 am, Erik Max Francis <m...@alcyone.comwrote:
Carl Banks wrote:
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.)

So your argument is purely about style, then. You just wish it were
written differently.
No, you misunderstand and/or misstate my position again. I realize I
wasn't as clear as I could have been. First of all it's not my
"argument": this is a tangent.

There would be a built-in empty, which invokes __empty__, in the same
way len invokes __len__. It would only be defined for container
types. (Iterators could choose whether to define it and it would mean
that the iterator is guaranteed stop on the next iteration. The
iterator is free to read and store the item. If the iterator doesn't
know whether it will stop, it must not define __empty__ or raise an
exception in it.) It would become the One Obvious Way to test for
emptiness. __nonzero__ would disappear and not be replaced with
anything, and objects would not have implicit boolean conversion.
Carl Banks
Jul 31 '08 #222
On Jul 30, 4:49 am, Ethan Furman <et...@stoneleaf.uswrote:
Carl Banks wrote:
On Jul 29, 6:42 pm, Matthew Fitzgibbons <eles...@nienna.orgwrote:
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

Even for those that did realize, and in fact hoped that that is what you
were attempting to accomplish,
I was not attempting to accomplish what you think I was.

I was looking for it, but I didn't want to see it. I didn't expect to
see it. I wanted to show that "if x" doesn't have the polymorphic
advantage people mindlessly claim it does by posing the challenge and
having people fail to meet it, and for the most part the examples that
met the challenge were for minor usages. Ok, someone wrote a filter
that truly benefits from polymorphism of "if x" against very different
types, but really, these use cases aren't all that common.

It's not like it's an everyday thing for you to write "if x" instead
of "if x!=0", and that it actually saves you from having to rewrite
the condition because later you decided to use a list.

So I stand by the point I was trying to make: for your average day-to-
day programming, the main benefit of "if x" is to save keystrokes. It
doesn't help your code become more polymophic in practice. A little
more polymorphic, yes. A lot, no.
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.
Pfft. The usage of "if x" might be Pythonic, but I think the best way
is the way Java does it.
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 wasn't playing Devil's advocate, I was playing the Devil. That's
why I did that. Sorry if it irritated people but I wasn't about to
those things distract me.
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.
I admit it! I downplay even successful examples because I just don't
like implicit booleans. What can I say, I'm an optimist.

I didn't see any custom matrix class, BTW. The only code I saw was
Steven D'Aprano filter which he still apparently expects me to take
his word for it that the alternative I proposed won't work, and Terry
Reedy's empty-enabled iterator. Oh, also Heiko Wundram's integer set.
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.
Sorry, but I must go on a crusade every once in awhile, whatever
damage it may cause my esteem. It's in my nature.
Carl Banks
Jul 31 '08 #223
Russ P. wrote:
On Jul 30, 1:07 am, Erik Max Francis <m...@alcyone.comwrote:
>Russ P. wrote:
>>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).
You suggested a syntax for testing non-emptiness (`x is not empty`)
which indicated a profound misunderstanding of what the `is` operator does.

You then acknowledged that there might be a problem because of the
implication if the `is` operator and weren't sure whether it would work
or not:

Oh, my. I wrote something like, "It would sure be nice to be able to
write

if x is not empty:

because it reads like natural language. Immediately after I posted it,
I thought, "oh, I'll bet some idiot takes that as a serious proposal."
Sure enough, some idiot did just that almost immediately.
Yes, all people are idiots for reading what you wrote, reading your
later realization that it was wrong, and taking both at face value.
I'll be sure never to make that mistake again!
And he is
still patronizing me for it.
No, I'm not patronizing you for your initial misstatement. I'm mocking
you for your pathetic and transparent attempt to backpedal away from it.
Just give it up, already.

--
Erik Max Francis && ma*@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 18 N 121 57 W && AIM, Y!M erikmaxfrancis
Drifting from woman-who-tries misconstrued / Shifting to woman-wise
-- Lamya
Jul 31 '08 #224
On Jul 30, 1:50*am, Carl Banks <pavlovevide...@gmail.comwrote:
On Jul 30, 1:58 am, "Russ P." <Russ.Paie...@gmail.comwrote:
On Jul 29, 10:33 pm, Carl Banks <pavlovevide...@gmail.comwrote:
On Jul 30, 1:15 am, "Russ P." <Russ.Paie...@gmail.comwrote:
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.
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
An __empty__ method could return True for my social life, ha ha. Does
__nonzero__ just mean __nonempty__?
Jul 31 '08 #225
On Jul 30, 7:05 pm, Erik Max Francis <m...@alcyone.comwrote:
Russ P. wrote:
On Jul 30, 1:07 am, Erik Max Francis <m...@alcyone.comwrote:
Russ P. wrote:
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).
You suggested a syntax for testing non-emptiness (`x is not empty`)
which indicated a profound misunderstanding of what the `is` operator does.
You then acknowledged that there might be a problem because of the
implication if the `is` operator and weren't sure whether it would work
or not:
Oh, my. I wrote something like, "It would sure be nice to be able to
write
if x is not empty:
because it reads like natural language. Immediately after I posted it,
I thought, "oh, I'll bet some idiot takes that as a serious proposal."
Sure enough, some idiot did just that almost immediately.

Yes, all people are idiots for reading what you wrote, reading your
later realization that it was wrong, and taking both at face value.
I'll be sure never to make that mistake again!
And he is
still patronizing me for it.

No, I'm not patronizing you for your initial misstatement. I'm mocking
you for your pathetic and transparent attempt to backpedal away from it.
Just give it up, already.

--
Erik Max Francis && m...@alcyone.com &&http://www.alcyone.com/max/
San Jose, CA, USA && 37 18 N 121 57 W && AIM, Y!M erikmaxfrancis
Drifting from woman-who-tries misconstrued / Shifting to woman-wise
-- Lamya
The reason I wrote that "it would be nice to be able to write"

if x is not empty:

is that it reads naturally. It was not an actual proposal, and the
fact that you took it as such was *your* mistake. I can understand
your misunderstanding one time, but you have now repeated it three
times, despite my (unnecessary) explanations. One more time, and you
graduate from idiot to moron.

Having said that, the syntax I wrote *could* conceivably work IF all
empty lists pointed to one empty list, just as all values set to None
actually point to the same None. That is possible, but probably not a
good idea.

Now read carefully: I DID NOT CLAIM THAT THIS IS THE WAY TO DO IT! Let
me repeat that for you: I DID NOT CLAIM THAT THIS IS THE WAY TO DO IT!
Did you get that, idiot?
Jul 31 '08 #226
On Wed, 30 Jul 2008 09:23:05 -0600, Matthew Fitzgibbons wrote:
If you're expecting a list (and only a list)
then your point makes sense. 'if x' can get you into trouble if you
_don't_ want its polymorphism.
"if x" is hardly unique in that way. If you're expecting a list, and only
a list, "len(x) != 0" will get you in trouble if somebody passes a string
or a dictionary. I don't see any reason why we should single out "if x"
as dangerous in the face of invalid types. With the exception of the "is"
and "is not" operators, nothing in Python is guaranteed to work with any
imaginable object. Even print can fail, if the object's __str__ method
raises an exception.

Although, if my function is expecting a list, my preference is to do:

if not isinstance(x, list):
raise SomeMeaningfulException()
# do stuff with the list

I put my type checking at the top of the function, so readers can
reference it easily.
And thus you break duck-typing and upset anybody who wants to pass a
sequence that doesn't inherit directly from list.

There are other (and arguably better, although more labour-intensive)
techniques for defensive programming that don't break duck-typing. You
can google for Look Before You Leap and Easier To Ask Forgiveness Than
Permission for more information. Alex Martelli has a fine recipe in the
Python Cookbook -- search for the recipe "Checking if an object has the
necessary attributes".

But in a nutshell, here's a toy example:

def spam(seq):
try:
seq.append
seq.extend
seq[0] = seq[0]
except Exception:
raise TypeError("argument isn't sufficiently sequence-like")
# No exceptions expected from here on
seq.append(seq[0])
seq.extend([1,2,3])
seq[0] = "spam"


--
Steven
Jul 31 '08 #227
On Wed, 30 Jul 2008 20:55:03 +0100, Matthew Woodcraft wrote:
On the other hand, iterators provide a clear example of problems with
"if x": __nonzero__ for iterators (in general) returns True even if they
are 'empty'.
How do you propose telling whether an iterator is empty?

That's a generic problem with any sort of lazy function. You don't know
if it has finished unless you try grabbing data from it.
For example, this function (which attempts to avoid making an expensive
call when not necessary) is buggy, but easy to write if you've been
taught that "if x" will work with any kind of object.

def frob(widgets, power):
if widgets:
frobber = Frobber(power) # expensive call
for widget in widgets:
frobber.frob(widget)

AFAIK there's no great solution to this problem. It's inherent in the way
lazy functions work. Certainly you can't replace the call to "if widgets"
with "if len(widgets)", because iterators don't have a length.

However, there is a good (but not great) solution:

def frob(widgets, power):
widgets = iter(widgets) # in case widgets is a sequence
try:
first = widgets.next()
except StopIteration:
# empty iterator, nothing to do
return None
frobber = Frobber(power) # expensive call
frobber.frob(widget)
for widget in widgets:
frobber.frob(widget)
--
Steven
Jul 31 '08 #228
Russ P. wrote:
The reason I wrote that "it would be nice to be able to write"

if x is not empty:

is that it reads naturally. It was not an actual proposal, and the
fact that you took it as such was *your* mistake.
...
Now read carefully: I DID NOT CLAIM THAT THIS IS THE WAY TO DO IT! Let
me repeat that for you: I DID NOT CLAIM THAT THIS IS THE WAY TO DO IT!
Did you get that, idiot?
So people who can read words but not minds are idiots. Go get 'em, tiger!

--
Erik Max Francis && ma*@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 18 N 121 57 W && AIM, Y!M erikmaxfrancis
If you turned right / You turned left / Or if you just walked out
ahead -- Anggun
Jul 31 '08 #229
Carl Banks wrote:
On Jul 30, 4:49 am, Ethan Furman <et...@stoneleaf.uswrote:
>Even for those that did realize, and in fact hoped that that is what you
were attempting to accomplish,

I was not attempting to accomplish what you think I was.

I was looking for it, but I didn't want to see it. I didn't expect to
see it. I wanted to show that "if x" doesn't have the polymorphic
advantage people mindlessly claim it does by posing the challenge and
having people fail to meet it, and for the most part the examples that
met the challenge were for minor usages. Ok, someone wrote a filter
that truly benefits from polymorphism of "if x" against very different
types, but really, these use cases aren't all that common.

It's not like it's an everyday thing for you to write "if x" instead
of "if x!=0", and that it actually saves you from having to rewrite
the condition because later you decided to use a list.
Actually, I use this construction a lot. But everybody has their own
style, and I'm certainly not going to tell you yours is wrong. One of
the fellows that works for me *loves* the (result if false, result if
true)[condition] style of immediate if's -- it's one of the first things
he learned about when studying Python, and he grins every time he talks
about it; *I* know it's not the best way to do it, and that it has it's
own set of gotchas -- so I made sure he was also aware of them, and uses
them where and when they won't blow up in our faces.
So I stand by the point I was trying to make: for your average day-to-
day programming, the main benefit of "if x" is to save keystrokes. It
doesn't help your code become more polymophic in practice. A little
more polymorphic, yes. A lot, no.
[snippitysnipsnip]
Carl Banks
Hmmm... well, I see your point. Unfortunately, even though it feels
incorrect to me, I do not (yet) have the breadth and depth of Python
experience to come up with an example that would display such exquisite
polymorphism. It also seems to me that such an example would be
non-trivial in nature. Perhaps starting a new thread with this
challenge, and adequate time (couple weeks at least, I would think)
would net you the smoking gun you were after.

At any rate, from my point of view, I like it. I like the visual
clarity and simplistic nature of "if x" -- it tells me "if x is
something", and I trust myself enough to know what I can do with the
something that is x. I also expect anyone else passing me a something
to know it has the appropriate interface to work with my code.

~Ethan~
Jul 31 '08 #230
On Jul 30, 8:03 pm, Erik Max Francis <m...@alcyone.comwrote:
Russ P. wrote:
The reason I wrote that "it would be nice to be able to write"
if x is not empty:
is that it reads naturally. It was not an actual proposal, and the
fact that you took it as such was *your* mistake.
...
Now read carefully: I DID NOT CLAIM THAT THIS IS THE WAY TO DO IT! Let
me repeat that for you: I DID NOT CLAIM THAT THIS IS THE WAY TO DO IT!
Did you get that, idiot?

So people who can read words but not minds are idiots. Go get 'em, tiger!
I don't know if you can read minds, but you seem to have a lot of
trouble reading words.

Can you read "it would be nice to be able to write ..."? Can you
understand what it means? Can you understand that it does *not* mean,
"one *should* be able to write ..."?

The really significant question here is why I waste my valuable time
with pedants like you.
Jul 31 '08 #231
On Thu, 31 Jul 2008 02:41:08 +0000, Steven D'Aprano wrote:
On Wed, 30 Jul 2008 09:23:05 -0600, Matthew Fitzgibbons wrote:
....
>Although, if my function is expecting a list, my preference is to do:

if not isinstance(x, list):
raise SomeMeaningfulException()
# do stuff with the list

I put my type checking at the top of the function, so readers can
reference it easily.

And thus you break duck-typing and upset anybody who wants to pass a
sequence that doesn't inherit directly from list.
Correction: delete "directly" from the above.
--
Steven
Jul 31 '08 #232
Russ P. wrote:

[snippers]
The reason I wrote that "it would be nice to be able to write"

if x is not empty:

is that it reads naturally.
[and more snippers]

Reads naturally? For whom? "Readability counts" does not mean "make it
sound like english as much as possible". There are good reasons for not
having computer languages written in human language. If that's really
what you want, go join Dave Parker and Flaming Thunder. Or write that
preprocessor that someone keeps yammering about and have it take code
the way you want to write it and convert it to actual Python. Would be
an interesting experiment, anyway.

~Ethan~
Jul 31 '08 #233
On Jul 30, 8:24 pm, "Russ P." <Russ.Paie...@gmail.comwrote:
On Jul 30, 8:03 pm, Erik Max Francis <m...@alcyone.comwrote:
Russ P. wrote:
The reason I wrote that "it would be nice to be able to write"
if x is not empty:
is that it reads naturally. It was not an actual proposal, and the
fact that you took it as such was *your* mistake.
...
Now read carefully: I DID NOT CLAIM THAT THIS IS THE WAY TO DO IT! Let
me repeat that for you: I DID NOT CLAIM THAT THIS IS THE WAY TO DO IT!
Did you get that, idiot?
So people who can read words but not minds are idiots. Go get 'em, tiger!

I don't know if you can read minds, but you seem to have a lot of
trouble reading words.

Can you read "it would be nice to be able to write ..."? Can you
understand what it means? Can you understand that it does *not* mean,
"one *should* be able to write ..."?

The really significant question here is why I waste my valuable time
with pedants like you.
Folks, I'm sorry for being so harsh here. But this guy keeps insisting
that I dispayed a "fundamental lack of understanding" of the correct
usage of "is" in Python. If that were true, I would have gladly
admitted it and dropped the matter. But it is completely false. The
simple fact is that I fully understood how "is" works in Python from
the first time I read about it -- as I'm sure most others here did
too. It just gets my goat that someone would latch onto some whimsical
suggestion I wrote to try to prove otherwise.

He did not need to play that silly little game, and he could have
easily avoided my insults had he not played it.
Jul 31 '08 #234
Russ P. wrote:
I don't know if you can read minds, but you seem to have a lot of
trouble reading words.

Can you read "it would be nice to be able to write ..."? Can you
understand what it means? Can you understand that it does *not* mean,
"one *should* be able to write ..."?
You're sure going on about a distinction without a difference for a guy
who childishly likes to call other people names. A reasonable person
would have long ago moved on instead of blaming others for not
immediately intuiting your thoughts, rather than straightforwardly
reading your words. Which, by the way, includes at least three people
other than myself.

But I'll bet the mindless namecalling is really working out for you.
Go, team, go!

--
Erik Max Francis && ma*@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 18 N 121 57 W && AIM, Y!M erikmaxfrancis
You are my martyr / I'm a vestige of a revolution
-- Lamya
Jul 31 '08 #235
Ethan Furman wrote:
If that's really what you want, go join Dave Parker and Flaming Thunder.
Best recommendation in this thread to date :)
Jul 31 '08 #236
On Jul 30, 9:27 pm, Erik Max Francis <m...@alcyone.comwrote:
Russ P. wrote:
I don't know if you can read minds, but you seem to have a lot of
trouble reading words.
Can you read "it would be nice to be able to write ..."? Can you
understand what it means? Can you understand that it does *not* mean,
"one *should* be able to write ..."?

You're sure going on about a distinction without a difference for a guy
who childishly likes to call other people names. A reasonable person
would have long ago moved on instead of blaming others for not
immediately intuiting your thoughts, rather than straightforwardly
reading your words. Which, by the way, includes at least three people
other than myself.

But I'll bet the mindless namecalling is really working out for you.
Go, team, go!
You earned the "childish name calling" by acting like a child -- with
your petty little game of trying to show that I don't understand a
basic concept in Python. As I said, your initial misunderstanding,
while silly, was at least forgivable. But your insistence on repeating
it time after time is not. It is truly pathetic.
Jul 31 '08 #237
On Tue, Jul 29, 2008 at 3:37 AM, Carl Banks <pa************@gmail.comwrote:
On Jul 28, 8:15 pm, Steven D'Aprano <st...@REMOVE-THIS-
cybersource.com.auwrote:
>On Mon, 28 Jul 2008 13:22:37 -0700, Carl Banks wrote:
On Jul 28, 10:00 am, Steven D'Aprano <st...@REMOVE-THIS-
cybersource.com.auwrote:
Cutting to the crux of the discussion...
>On Sun, 27 Jul 2008 23:45:26 -0700, Carl Banks wrote:
I want something where "if x" will do but a simple explicit test
won't.
>Explicit tests aren't simple unless you know what type x is. If x could
be of any type, you can't write a simple test. Does x have a length? Is
it a number? Maybe it's a fixed-length circular length, and the length
is non-zero even when it's empty? Who knows? How many cases do you need
to consider?
Use case, please. I'm asking for code, not arguments. Please give me a
piece of code where you can write "if x" that works but a simple
explicit test won't.

I gave you a piece of code, actual code from one of my own projects. If
you wouldn't accept that evidence then, why would you accept it now?

I would accept as "evidence" something that satisfies my criteria,
which your example did not: it could have easily (and more robustly)
been written with a simple explicit test. I am looking for one that
can't.

You keep bringing up this notion of "more complex with no benefit",
which I'm simply not interested in talking about that at this time,
and I won't respond to any of your points. I am seeking the answer to
one question: whether "if x" can usefully do something a simple
explicit test can't. Everyone already knows that "if x" requires
fewer keystrokes and parses to fewer nodes.
I'm really not sure where you're going with this or what you're trying
to prove. "if x" is a duck-type test for a boolean value. Obviously if
you know the type and want a more *specific* test, then you can use an
explicit one. Any time you don't know or don't care about a more
specific type than "something which probably is boolean true", or any
time where you know the boolean semantics of the type and want to drop
some typing, you can use "if x". The more specific test is what you'd
use if you want more specific results. What's complicated about this
idea?
Jul 31 '08 #238
Steven D'Aprano wrote:
On Wed, 30 Jul 2008 09:23:05 -0600, Matthew Fitzgibbons wrote:
>If you're expecting a list (and only a list)
then your point makes sense. 'if x' can get you into trouble if you
_don't_ want its polymorphism.

"if x" is hardly unique in that way. If you're expecting a list, and only
a list, "len(x) != 0" will get you in trouble if somebody passes a string
or a dictionary. I don't see any reason why we should single out "if x"
as dangerous in the face of invalid types. With the exception of the "is"
and "is not" operators, nothing in Python is guaranteed to work with any
imaginable object. Even print can fail, if the object's __str__ method
raises an exception.

>Although, if my function is expecting a list, my preference is to do:

if not isinstance(x, list):
raise SomeMeaningfulException()
# do stuff with the list

I put my type checking at the top of the function, so readers can
reference it easily.

And thus you break duck-typing and upset anybody who wants to pass a
sequence that doesn't inherit directly from list.

There are other (and arguably better, although more labour-intensive)
techniques for defensive programming that don't break duck-typing. You
can google for Look Before You Leap and Easier To Ask Forgiveness Than
Permission for more information. Alex Martelli has a fine recipe in the
Python Cookbook -- search for the recipe "Checking if an object has the
necessary attributes".

But in a nutshell, here's a toy example:

def spam(seq):
try:
seq.append
seq.extend
seq[0] = seq[0]
except Exception:
raise TypeError("argument isn't sufficiently sequence-like")
# No exceptions expected from here on
seq.append(seq[0])
seq.extend([1,2,3])
seq[0] = "spam"

Yes, I know it breaks duck typing, which is why I do it only very
rarely, and never with e.g. sequence types. If I use ifinstance for type
checking, it's because I need some _very_ specific class, almost always
one that I wrote. My more usual use case for ifinstance is to figure out
how to handle a particular object using introspection.

That said, your example is still helpful. It's a good approach, and I
should use it more often. Although I'd also lean toward hasattr and
iscallable and ordinary ifs instead of the try ... except where
possible. Depending on what you put in the try ... except, you risk
masking legit exceptions.

Ahhh, Programing. Where no rule of thumb seems to last five minutes.

-Matt
Jul 31 '08 #239
Steven D'Aprano wrote:
On Wed, 30 Jul 2008 09:23:05 -0600, Matthew Fitzgibbons wrote:
>If you're expecting a list (and only a list)
then your point makes sense. 'if x' can get you into trouble if you
_don't_ want its polymorphism.

"if x" is hardly unique in that way. If you're expecting a list, and only
a list, "len(x) != 0" will get you in trouble if somebody passes a string
or a dictionary. I don't see any reason why we should single out "if x"
as dangerous in the face of invalid types. With the exception of the "is"
and "is not" operators, nothing in Python is guaranteed to work with any
imaginable object. Even print can fail, if the object's __str__ method
raises an exception.
Forgot respond to this point. I heartily agree. :) I singled out 'if x'
only because that's the specific example under scrutiny. I think you and
I are pretty much in agreement.

-Matt
Jul 31 '08 #240
Matthew Fitzgibbons wrote:
Steven D'Aprano wrote:
>On Wed, 30 Jul 2008 09:23:05 -0600, Matthew Fitzgibbons wrote:
>>If you're expecting a list (and only a list)
then your point makes sense. 'if x' can get you into trouble if you
_don't_ want its polymorphism.

"if x" is hardly unique in that way. If you're expecting a list, and
only a list, "len(x) != 0" will get you in trouble if somebody passes
a string or a dictionary. I don't see any reason why we should single
out "if x" as dangerous in the face of invalid types. With the
exception of the "is" and "is not" operators, nothing in Python is
guaranteed to work with any imaginable object. Even print can fail, if
the object's __str__ method raises an exception.

>>Although, if my function is expecting a list, my preference is to do:

if not isinstance(x, list):
raise SomeMeaningfulException()
# do stuff with the list

I put my type checking at the top of the function, so readers can
reference it easily.

And thus you break duck-typing and upset anybody who wants to pass a
sequence that doesn't inherit directly from list.

There are other (and arguably better, although more labour-intensive)
techniques for defensive programming that don't break duck-typing. You
can google for Look Before You Leap and Easier To Ask Forgiveness Than
Permission for more information. Alex Martelli has a fine recipe in
the Python Cookbook -- search for the recipe "Checking if an object
has the necessary attributes".

But in a nutshell, here's a toy example:

def spam(seq):
try:
seq.append
seq.extend
seq[0] = seq[0]
except Exception:
raise TypeError("argument isn't sufficiently sequence-like")
# No exceptions expected from here on
seq.append(seq[0])
seq.extend([1,2,3])
seq[0] = "spam"


Yes, I know it breaks duck typing, which is why I do it only very
rarely, and never with e.g. sequence types. If I use ifinstance for type
checking, it's because I need some _very_ specific class, almost always
one that I wrote. My more usual use case for ifinstance is to figure out
how to handle a particular object using introspection.

That said, your example is still helpful. It's a good approach, and I
should use it more often. Although I'd also lean toward hasattr and
iscallable and ordinary ifs instead of the try ... except where
possible. Depending on what you put in the try ... except, you risk
masking legit exceptions.

Ahhh, Programing. Where no rule of thumb seems to last five minutes.

-Matt
--
http://mail.python.org/mailman/listinfo/python-list
Where by ifinstance I mean isinstance and by iscallable I mean callable.

*hides*

-Matt
Jul 31 '08 #241
Steven D'Aprano wrote:
>On Wed, 30 Jul 2008 20:55:03 +0100, Matthew Woodcraft wrote:
>On the other hand, iterators provide a clear example of problems with
"if x": __nonzero__ for iterators (in general) returns True even if they
are 'empty'.
How do you propose telling whether an iterator is empty?
That's a generic problem with any sort of lazy function. You don't know
if it has finished unless you try grabbing data from it.
Of course.

The point is that if you tell people that "if x" is the standard way to
check for emptiness, and also support a general principle along the
lines of "write your function using the interfaces you expect, and call
it using the object you have", you should expect to end up with bugs of
this sort.

>For example, this function (which attempts to avoid making an expensive
call when not necessary) is buggy, but easy to write if you've been
taught that "if x" will work with any kind of object.

def frob(widgets, power):
if widgets:
frobber = Frobber(power) # expensive call
for widget in widgets:
frobber.frob(widget)
AFAIK there's no great solution to this problem. It's inherent in the way
lazy functions work. Certainly you can't replace the call to "if widgets"
with "if len(widgets)", because iterators don't have a length.
I'm not a fan of len() for testing emptiness. But it would have been
better in this case, because it would have converted a hard-to-find
performance bug into an obvious exception.

>However, there is a good (but not great) solution:

def frob(widgets, power):
widgets = iter(widgets) # in case widgets is a sequence
try:
first = widgets.next()
except StopIteration:
# empty iterator, nothing to do
return None
frobber = Frobber(power) # expensive call
frobber.frob(widget)
for widget in widgets:
frobber.frob(widget)
I would use the following low-tech way:

def frob(widgets, power):
frobber = None
for widget in widgets:
if frobber is None:
frobber = Frobber(power)
frobber.frob(widget)

-M-
Jul 31 '08 #242
On Thu, 31 Jul 2008 22:01:48 +0100, Matthew Woodcraft wrote:
Steven D'Aprano wrote:
>>On Wed, 30 Jul 2008 20:55:03 +0100, Matthew Woodcraft wrote:
>>On the other hand, iterators provide a clear example of problems with
"if x": __nonzero__ for iterators (in general) returns True even if
they are 'empty'.
>How do you propose telling whether an iterator is empty? That's a
generic problem with any sort of lazy function. You don't know if it
has finished unless you try grabbing data from it.

Of course.

The point is that if you tell people that "if x" is the standard way to
check for emptiness, and also support a general principle along the
lines of "write your function using the interfaces you expect, and call
it using the object you have", you should expect to end up with bugs of
this sort.
I'm not sure that an occasional performance hit justifies calling it a
bug. I suppose you might come up with a scenario or two where it really
is a problem, but then I'm also free to imagine scenarios where calling
len(obj) takes a massive performance hit, or has irreversible side
effects.

>>For example, this function (which attempts to avoid making an
expensive call when not necessary) is buggy, but easy to write if
you've been taught that "if x" will work with any kind of object.

def frob(widgets, power):
if widgets:
frobber = Frobber(power) # expensive call
for widget in widgets:
frobber.frob(widget)
But note that the code still does the right thing even if widgets is
empty. The only problem is that it needlessly calls Frobber. Frankly,
that would have to be *really* expensive before I would even bother using
the more complicated code. This is a good example of premature
optimization.

>AFAIK there's no great solution to this problem. It's inherent in the
way lazy functions work. Certainly you can't replace the call to "if
widgets" with "if len(widgets)", because iterators don't have a length.

I'm not a fan of len() for testing emptiness. But it would have been
better in this case, because it would have converted a hard-to-find
performance bug into an obvious exception.
At the cost of wrongly raising a exception for perfectly good arguments,
namely non-empty iterators.

--
Steven
Jul 31 '08 #243
On Jul 28, 12:15*pm, Kay Schluehr <kay.schlu...@gmx.netwrote:
On 28 Jul., 06:42, "Russ P." <Russ.Paie...@gmail.comwrote:


On Jul 27, 8:58 pm, castironpi <castiro...@gmail.comwrote:
On Jul 27, 2:39 pm, Bruno Desthuilliers
<bdesth.quelquech...@free.quelquepart.frwrote:
Derek Martin a écrit :
It's bad programming, but the world is full of bad programmers, and we
don't always have the choice not to use their code. *Isn't one of
Python's goals to minimize opportunities for bad programming?
Nope. That's Java's goal. Python's goals are to maximize opportunities
for good programming, which is quite different.
Oh, gosh, that is so clever. What a bunch of crap.
+1 QOTW
Do you realize what an insult that is to everyone else who has posted
here in the past week?

Nothing glues a community together so well as a common enemy. Or even
better: two enemies i.e. Perl and Java in Pythons case. On the other
hand, some enemies have to be ignored or declared to be not an enemy
( Ruby ), although oneself is clearly an enemy for them. The same
antisymmetry holds for Python and Java. Java is an enemy for Python
but Python is not worth for Java to be an enemy as long as it can be
ignored. C++ and Java are enemies for each other. Same holds for Java
and C#.- Hide quoted text -

- Show quoted text -
Help... being... sucked into... black hole... inside a... Klein...
bottle...
Jul 31 '08 #244
Steven D'Aprano wrote:
>On Thu, 31 Jul 2008 22:01:48 +0100, Matthew Woodcraft wrote:
>The point is that if you tell people that "if x" is the standard way to
check for emptiness, and also support a general principle along the
lines of "write your function using the interfaces you expect, and call
it using the object you have", you should expect to end up with bugs of
this sort.
I'm not sure that an occasional performance hit justifies calling it a
bug. I suppose you might come up with a scenario or two where it really
is a problem, but then I'm also free to imagine scenarios where calling
len(obj) takes a massive performance hit, or has irreversible side
effects.
Of course performance problems can be bugs! And it was explicit in my
example that this was supposed to be such a case.

But here, have an example where it's a non-performance bug:

def load_widgets(self, widgets):
if not widgets:
raise ValueError("no widgets specified")
self._prepare_for_widgets()
for widget in widgets:
self._load_widget(widget)
self._is_widgetty = True

This way you can end up with an object in an invalid state.

>I'm not a fan of len() for testing emptiness. But it would have been
better in this case, because it would have converted a hard-to-find
performance bug into an obvious exception.
At the cost of wrongly raising a exception for perfectly good arguments,
namely non-empty iterators.
Sure, which will be fixed when the code passing an iterator is first
tested, whether the iterator is empty or not. It's the errors which pass
silently that are most dangerous.
As I said, I'm not a fan of len() for testing emptiness. But "if x"
isn't good either. Often I end up rearranging things so I can get rid of
the explicit test altogether, but there can be a cost in readability.

I think any Python-like language would be better off with an explicit
way of asking 'is this container empty?'.

-M-

Jul 31 '08 #245
On Jul 31, 1:27 pm, "Chris Mellon" <arka...@gmail.comwrote:
I'm really not sure where you're going with this or what you're trying
to prove. "if x" is a duck-type test for a boolean value. Obviously if
you know the type and want a more *specific* test, then you can use an
explicit one. Any time you don't know or don't care about a more
specific type than "something which probably is boolean true", or any
time where you know the boolean semantics of the type and want to drop
some typing, you can use "if x". The more specific test is what you'd
use if you want more specific results. What's complicated about this
idea?
Many people trumpet that "if x" makes your code more polymorphic
whenever this comes up--in fact you just repeated the claim--without
ever considering how rarely this more extensive polymorphism comes up
in practice. I was calling them out to say "prove to me that it
actually happens".

I believe it's very rare not to know enough about the expected type
that explicit tests won't work. We've uncovered a few examples of it
in this thread, but IMO we haven't uncovered any sort of broad, wide-
ranging use cases.
Carl Banks
Aug 1 '08 #246
On Jul 31, 12:13 am, Ethan Furman <et...@stoneleaf.uswrote:
Carl Banks wrote:
So I stand by the point I was trying to make: for your average day-to-
day programming, the main benefit of "if x" is to save keystrokes. It
doesn't help your code become more polymophic in practice. A little
more polymorphic, yes. A lot, no.

Hmmm... well, I see your point. Unfortunately, even though it feels
incorrect to me, I do not (yet) have the breadth and depth of Python
experience to come up with an example that would display such exquisite
polymorphism. It also seems to me that such an example would be
non-trivial in nature.
Wrong on both counts. Let me give you a hint.

Take integers and lists. Count how many methods the two types have in
common. By my reckoning, they are:

__add__, __iadd__, __mul__, _imul__, __str__, __repr__, and
__nonzero__.

Also there are __getattribute__ and __setattr__, but lists and ints
share no common attributes. I don't think ints have any at all aside
from the special methods.

What this means is: any code that can work for both ints and lists
must use only these methods (this is not quite correct, but mostly
is). That eliminates probably 99.9% of code right off the bat.

Then you have to consider that some code that does use only these
attributes does something useful only for either ints or lists, not
both. Take this simple example:

def foil(a,b,c,d):
return a*b + a*d + b*c + b*d

This code works if a and c are both ints, or are both lists (while b
and d would have to be ints). It does something useful for ints and
other numeric types, but does it do anything useful for lists?

Third, there are cases where you have code that works for both ints
and lists, that does do something useful for both, but it makes no
sense to apply "if x" to it.

def print_if_true(x):
if x:
print x

This little piece of code might actually come in handy here and there,
but would it end up being used for numeric types a whole lot? It
seems like if you have an empty list you might reasonably want to
print nothing at all, but when you have a zero integer you usually
want to print the zero.

(However, you might reasonably want to print some object unless it's
None. You could then use this one function to handle that case as
well as the case with empty lists, instead of defining two functions,
like so:

print_if_not_empty(x):
if len(x)!=0:
print x

print_if_not_None(x):
if x is not None:
print x

But wait! What if you had a value that could be either an integer or
None? You can't use the "if x" variant because x could be False. So
you'd have to define the "if x is not None" variant anyway. I might
use the "if x" variant in throwaway scripts, but for anything
production I would prefer the explicit variants, partially because, as
shown above, even when "if x" does rear it's polymoprhic head, it
doesn't necessarily buy you much.

Nevertheless, I think this is probably the best example of the
enhanced polymorphism of "if x" yet. I'm kind of surprised no one
came up with it.)

In general, the ability to take advantage of "if x" polymorphism
across numeric, container, and other types depends on the something/
nothing dichotomy to be applicable. Something versus nothing is a
useless concept most of the time, but occasionally finds use in human
interaction cases such as printing.

So there you have it. This is why I didn't expect anyone to come up
with a good example: you just don't have a lot to work with.

Carl Banks
Aug 1 '08 #247
On Jul 31, 11:44 pm, Carl Banks <pavlovevide...@gmail.comwrote:
[snip excellent explanation of why it's hard to for "if x" to be
extensively polymorphic]
By the way, one thing I forgot to mention is Matt Fitzgibbons' filter
example.

As I said, it's hard to write code that works for both numeric and
container types because they share so few methods. However, sometimes
you don't know ahead of time what methods are used! When you're doing
functional programming you might pass in a method that calls the
appropriate method, like so:

def apply_if_true(func,x):
if x:
func(x)

The function f could use methods appropriate for ints when x is an
int, and for lists when x is an int.

I did downplay this, because frankly, not many programmers use
functional methods this extensively. But one should also note that
you could pass in the test as well:

def apply_if_condition(func,cond,x):
if cond(x):
func(x)

Thus this usage of "if x" arguably could be considered "replaceable
with a simple explicit test". But in the interests of harmony I
didn't push the point, and it really would have been stretching the
spirit of what I was trying to prove.
Carl Banks
Aug 1 '08 #248
Carl Banks wrote:
If you recall, I agreed with his statement. Would you like to claim
that I don't understand the fundamentals of Python?
Since you've invented this connection out of nowhere, not particularly.
I've never said anything about _anyone_ not understanding the
fundamentals of Python, so you're just trying to make up controversy here.

--
Erik Max Francis && ma*@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 18 N 121 57 W && AIM, Y!M erikmaxfrancis
We all breathe the same air. We all cherish our children's future.
And we are all mortal. -- John F. Kennedy
Aug 1 '08 #249
On 2008-08-01, Carl Banks <pa************@gmail.comwrote:
On Jul 31, 1:27 pm, "Chris Mellon" <arka...@gmail.comwrote:
>I'm really not sure where you're going with this or what you're trying
to prove. "if x" is a duck-type test for a boolean value. Obviously if
you know the type and want a more *specific* test, then you can use an
explicit one. Any time you don't know or don't care about a more
specific type than "something which probably is boolean true", or any
time where you know the boolean semantics of the type and want to drop
some typing, you can use "if x". The more specific test is what you'd
use if you want more specific results. What's complicated about this
idea?

Many people trumpet that "if x" makes your code more polymorphic
whenever this comes up--in fact you just repeated the claim--without
ever considering how rarely this more extensive polymorphism comes up
in practice. I was calling them out to say "prove to me that it
actually happens".

I believe it's very rare not to know enough about the expected type
that explicit tests won't work. We've uncovered a few examples of it
in this thread, but IMO we haven't uncovered any sort of broad, wide-
ranging use cases.
I was reading this thread and was wondering about the following problem.

I have a loop that continuously calculates something. I also have a
producer that may produce extra input that can influence the
calculations. The producer can also indicate the loop should finish.

So the result of produce can be three things:

1) A not empty sequence; indicating available input.

2) An empty sequence; indicating no input available now.

3) None; indicating the end of the calculations.
So the loop essentially looks like this:

while 1:
extra = produce()
if extra is None:
break
for el in extra:
adjust_with(el)
calculate()
I now have the following question for people who argue that "if x"
is more polymorphic. I could subclass list, so that instances
of this new sequence would always behave as true, even if they are
empty. I could then rewrite my loop as follows:

while 1:
extra = produce()
if not extra:
break
for el in extra:
adjust_with(el)
calculate()

Is this second loop now more polymorphic as the first?

Personnaly I would argue that the first loop with the more specific
test is more polymorphic in this case, as it works with the standard
sequence semantics of python; so the first loop will work with
produce, producing any kind of sequence while the second loop
will only work with produce producing a specific kind of sequence.

--
Antoon Pardon
Aug 1 '08 #250

This thread has been closed and replies have been disabled. Please start a new discussion.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.