Attack a sacred Python Cow

A

Anders J. Munch

Ethan said:
reinforce the impression that he is unaware of the double-underscore
functions and what they do and how they work.

Only if your newsreader malfunctioned and refused to let you read the rest of
the paragraph.

Of course I know what __nonzero__ does.

regards, Anders
 
C

Carl Banks

Carl said:
[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)

I find myself doing things like this surprisingly often. All you've done
is move the decision as to what function is applied to x elsewhere. Like
a factory, for example. I could see using something like this where func
prepares object x to be inserted into a database, and you want to make
sure x is meaningful first.

def add_to_db(prep_func, x):
if x:
entry = prep_func(x)
add_to_db(entry)

'if x' strikes me as better for this case because you might want to
accept a non-empty list (or some other objects) but reject non-empty
lists. 'if x is None' would not work. It still may be susceptible to the
empty iterator problem, depending on what prep_func does.

What if what you consider to be "meaningful" doesn't happen to
coincide with what Python considers to be "something". For instance,
what if being non-negative is what makes an integer meaningful? You
can't use "if x" for that. What if any list, including an empty one,
is meaningful, but you want to indicate the possibility of an
unmeaningful value by passing None? You can't use "if x" for that.

So, you might address this issue by doing something like this:

def add_to_db(prep_func, is_meaningful, x):
if is_meaningful(x):
entry = prep_func(x)
add_to_db(entry

But if you do that, what has the polymorphism of "if x" gained you?

The thing it gained for you before is not having to pass in a
condition: whether x was a sequence, number, or whatever, the same
condition could be used, and thus you avoided considerable
complexity. But if you have to perform tests for which the implicit
boolean doesn't work, that complexity has to be added to the code
anyway.

That matters in the context of this discussion because it limits the
usefulness of the polymorphism of "if x" for this functional idiom:
"if x" only helps you if you have no need for tests that it can't
handle.

[snip]

Carl Banks
 
E

Ethan Furman

Anders said:
Only if your newsreader malfunctioned and refused to let you read the
rest of the paragraph.

Of course I know what __nonzero__ does.

regards, Anders

Anders, my apologies. Since reading that post I came across some other
replies you made and realized quite cleary that you do know what you're
doing.

By way of explanation as to why I was confused: the "even if we find
out" suggested to me that you weren't aware of the calling pattern for
"if x" (__nonzero__ if defined, otherwise __len__ if defined). Also, in
your sample code you defined a class C, then assigned the variable c
using "c=get_a_C()", and get_a_C was never defined. Then you posed the
question, "if get_a_C might ever return None"... who knows? You never
said what get_a_C did; furthermore, whether or not get_a_C returns a C
object or None is completely irrelevant to whether or not __nonzero__ is
defined or attribute_is_nonnegative is defined.

FWIW, I completely agree with you as far as naming functions that deal
with less consequential attributes; for an attribute that is central to
the object, I agree with using __nonzero__. For example:
--------------------------------------------------------------------
class Human(object):
def __init__(self, hair, eye, skin):
self.alive = True
self.haircolor = hair
self.eyecolor = eye
self.skincolor = skin
def __nonzero__(self):
return self.alive
def hair_color_is_red(self):
return self.haircolor in ['red', 'strawberry blonde', 'auburn']
def eye_color_is_green(self):
return self.eyecolor in ['green', 'hazel', 'teal']
def skin_color_is_medium(self):
return self.skincolor in ['tanned', 'brown', 'burnished']
def die(self):
self.alive = False
def talk(self):
if self:
print "I don't want to go in the cart!"
def walk(self, where=''):
if self:
if not where:
print "Just taking a stroll..."
else:
print "On my way to " + where

--> from human import Human
--> charles = Human('blonde', 'teal', 'sunburnt')
--> charles
--> charles = Human('blonde', 'teal', 'sunburnt')
--> if charles:
.... charles.eye_color_is_green()
.... charles.walk("away from the cart...")
.... charles.talk()
....
True
On my way to away from the cart...
I don't want to go in the cart!
--------------------------------------------------------------------

If charles is alive is rather important to the whole object -- if he's
dead, he's not walkin' and talkin'! ;)

~Ethan~
 
R

Russ P.

Many of you probably consider me a real jerk. Well, I guess I have
been one here. Believe it or not, I'm actually a pretty nice guy in
real life. Something about the detachment and (partial) anonymity of
being online makes me write things I would never say in person. For
that I apologize.

I had two major fights just on this thread, not to mention a couple of
"minor" ones. Although I believe I was treated unfairly at times,
that was no excuse to resort to insulting replies and "childish name
calling," as one person called it.

From this point on, I will try to stay away from any debate about
anything controversial here on comp.lang.python.

Go ahead, say what you will. Take pot shots if you wish. Maybe I
deserve some. But in the end, you will be saying more about yourself
than about me. I will not reply.
 
T

Terry Reedy

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

I think of Python code as 'generic' rather than 'polymorphic'. I am not
sure if that is a real difference or not, since I am a bit fuzzy on the
meaning of 'polymorphic' in this context.

The generality of 'if x:' depends on the context. If x is defined as a
number by doc or previous code (or possibly even by subsequent code),
then 'if x:' is equivalent to 'if x != 0:'. At this point, it is a
stylistic argument which to use.

But here is an example where 'if x:' is more generic.

def solve(a,b):
'a and b such that b/a exists'
if a:
return a/b
else:
raise ValueError('a not invertible, cannot solve'

Now suppose we have a matrix class (2x2 for simplicity and realism).
Its __bool__ (3.0) method implements 'is non-singular'. As written
above, solve(mat,vec) works (with compatible mat and vec sizes), but it
would not with 'if a != 0:'.

Of course, the issue goes away by not looking before the leap:

def solve(a,b):
return a/b
# let callers deal with exceptions
or
try:
return a/b
except...
# raise customized error
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.

Numbers and sequences are both sortable with the same algorithm if it is
written to be generic. However, 0 is nothing special when sorting, so
'if x:' would not be used.

All collections are (or should be) iterable. But a boolean test is not
part of the current iteration protocol. One might want to test whether
the iterable starts with anything before setting things up, but that
either exclude most iterators or requires wrapping them in a lookahead
class with a __bool__ method.

In general, asking code to apply across numeric, container, and other
classes is asking too much. Python code can be generic only within
protocol/interface categories such as number-like, sortable, and
iterable. But making tests too specific can unnecessarily prevent even
that.
> Something versus nothing is a useless concept most of the time, but
> occasionally finds use in human interaction cases such as printing.

It is sometimes useful within categories of classes, as in my solve example.

Terry Jan Reedy
 
M

Matthew Fitzgibbons

Carl said:
Carl said:
[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)
I find myself doing things like this surprisingly often. All you've done
is move the decision as to what function is applied to x elsewhere. Like
a factory, for example. I could see using something like this where func
prepares object x to be inserted into a database, and you want to make
sure x is meaningful first.

def add_to_db(prep_func, x):
if x:
entry = prep_func(x)
add_to_db(entry)

'if x' strikes me as better for this case because you might want to
accept a non-empty list (or some other objects) but reject non-empty
lists. 'if x is None' would not work. It still may be susceptible to the
empty iterator problem, depending on what prep_func does.

What if what you consider to be "meaningful" doesn't happen to
coincide with what Python considers to be "something". For instance,
what if being non-negative is what makes an integer meaningful? You
can't use "if x" for that. What if any list, including an empty one,
is meaningful, but you want to indicate the possibility of an
unmeaningful value by passing None? You can't use "if x" for that.

So, you might address this issue by doing something like this:

def add_to_db(prep_func, is_meaningful, x):
if is_meaningful(x):
entry = prep_func(x)
add_to_db(entry

But if you do that, what has the polymorphism of "if x" gained you?

The thing it gained for you before is not having to pass in a
condition: whether x was a sequence, number, or whatever, the same
condition could be used, and thus you avoided considerable
complexity. But if you have to perform tests for which the implicit
boolean doesn't work, that complexity has to be added to the code
anyway.

Of course. If a chunk of code already does what you want it to, then you
can use it. Otherwise you have to do something different. I was just
pointing out that 'if x' often does what I want it to. Sometimes it
doesn't, so I do something different.
That matters in the context of this discussion because it limits the
usefulness of the polymorphism of "if x" for this functional idiom:
"if x" only helps you if you have no need for tests that it can't
handle.

[snip]

Carl Banks

By this argument, all code is limiting. Obviously, no code can do what
it can't.

We're not getting anywhere; it's past time to kill this one off.

-Matt
 
C

Carl Banks

I think of Python code as 'generic' rather than 'polymorphic'. I am not
sure if that is a real difference or not, since I am a bit fuzzy on the
meaning of 'polymorphic' in this context.

The generality of 'if x:' depends on the context. If x is defined as a
number by doc or previous code (or possibly even by subsequent code),
then 'if x:' is equivalent to 'if x != 0:'. At this point, it is a
stylistic argument which to use.

But here is an example where 'if x:' is more generic.

def solve(a,b):
'a and b such that b/a exists'
if a:
return a/b
else:
raise ValueError('a not invertible, cannot solve'

Now suppose we have a matrix class (2x2 for simplicity and realism).
Its __bool__ (3.0) method implements 'is non-singular'. As written
above, solve(mat,vec) works (with compatible mat and vec sizes), but it
would not with 'if a != 0:'.

I see what you're saying, even though this example turns out to be
pretty bad in practice.

(Practically speaking, you hardly ever write code for both matrices
and scalars, because the optimal way for matrices would be convoluted
and opaque for scalars, though scalars can sometimes be fed into
matrix code as a degenerate case. Also, checking the condition of the
matrix by calculating and comparing the determinant to zero is like
comparing float equality without a tolerance, only much, much worse.)

But instead of a matrix, take a vector (which has a better chance of
being used in code designed for scalars) and define a zero-length
vector as false, and that could be a good example.

In general, asking code to apply across numeric, container, and other
classes is asking too much. Python code can be generic only within
protocol/interface categories such as number-like, sortable, and
iterable. But making tests too specific can unnecessarily prevent even
that.

At some point we have to throw our hands up and realize that if we're
working with custom classes with varying degrees of nonconformance,
there is nothing we can do that's safe.

It is sometimes useful within categories of classes, as in my solve example.

I'm going to say no.

Let's take your matrix example: you defined singularity to be false,
but singularity can't reasonably be mapped to the concept of nothing.
For "nothing" I would think you'd want a 0x0 matrix. Something vs
nothing also implies that all objects should have a boolean value.
So, assuming boolean is connected to a matrices singularity, what
should be the boolean value of non-square matrices?

No, I'm going to have to disagree very strongly with this.
Nonzeroness is useful. Emptiness is useful. Singularity a kind of
useful. Nothing and something are vague, ill-defined, ad hoc concepts
that mean nothing to a computer. Have you ever seen an algorithm that
says "if x is something"?

Something and nothing do seem to come into play occasionally in that,
when interacting with humans (be it the user or programmer), it
sometimes--not nearly always--makes sense to treat nonzero and empty
in the same way. But there's no particular reason to apply the
concepts of something and nothing beyond this pragmatic use.


Carl Banks
 
C

Carl Banks

I see what you're saying, even though this example turns out to be
pretty bad in practice.

(Practically speaking, you hardly ever write code for both matrices
and scalars, because the optimal way for matrices would be convoluted
and opaque for scalars, though scalars can sometimes be fed into
matrix code as a degenerate case. Also, checking the condition of the
matrix by calculating and comparing the determinant to zero is like
comparing float equality without a tolerance, only much, much worse.)

But instead of a matrix, take a vector (which has a better chance of
being used in code designed for scalars) and define a zero-length
vector as false, and that could be a good example.


At some point we have to throw our hands up and realize that if we're
working with custom classes with varying degrees of nonconformance,
there is nothing we can do that's safe.



I'm going to say no.

Let's take your matrix example: you defined singularity to be false,
but singularity can't reasonably be mapped to the concept of nothing.
For "nothing" I would think you'd want a 0x0 matrix. Something vs
nothing also implies that all objects should have a boolean value.
So, assuming boolean is connected to a matrices singularity, what
should be the boolean value of non-square matrices?

No, I'm going to have to disagree very strongly with this.
Nonzeroness is useful. Emptiness is useful. Singularity a kind of
useful. Nothing and something are vague, ill-defined, ad hoc concepts
that mean nothing to a computer. Have you ever seen an algorithm that
says "if x is something"?

Something and nothing do seem to come into play occasionally in that,
when interacting with humans (be it the user or programmer), it
sometimes--not nearly always--makes sense to treat nonzero and empty
in the same way. But there's no particular reason to apply the
concepts of something and nothing beyond this pragmatic use.

Carl Banks
 
C

Carl Banks

At some point we have to throw our hands up and realize that if we're
working with custom classes with varying degrees of nonconformance,
there is nothing we can do that's safe.

And I want to make clear I'm not trying to downplay your example
here. The example you gave me definitely fits the criteria of being a
useful "if x" that can't be replaced by a simple explicit test, at
least after my alteration to a vector example.

It's a concern when you write code that breaks realistic custom
classes, but really concerning when it breaks built-in classes.


Carl Banks
 
M

Michele Simionato

Letting "self" (or whatever the first argument was) be implied in
".cat" does absolutely *NOTHING* to change the internal workings of
the Python interpreter. It's a very simple idea that you insist on
making complicated. As I said, I could write a pre-processor myself to
implement it in less than a day.

I implemented such a pre-processor 6+ years ago and I am absolutely
sure
I was not to first one to reinvent this particular wheel. But now I
have grown up
and I am happy with self, because sometimes it can
be named cls, mcl, obj or anything else, and I take advantage of this
fact in my code. self is more readable than a dot and there is
no point in making a special case for it.

Michele Simionato
 
P

Paul McGuire

Help... being... sucked into... black hole... inside a... Klein...
bottle...- Hide quoted text -

- Show quoted text -

... which is inside... the black hole...
 
A

Antoon Pardon

I think of Python code as 'generic' rather than 'polymorphic'. I am not
sure if that is a real difference or not, since I am a bit fuzzy on the
meaning of 'polymorphic' in this context.

The generality of 'if x:' depends on the context. If x is defined as a
number by doc or previous code (or possibly even by subsequent code),
then 'if x:' is equivalent to 'if x != 0:'. At this point, it is a
stylistic argument which to use.

But here is an example where 'if x:' is more generic.

def solve(a,b):
'a and b such that b/a exists'
if a:
return a/b
else:
raise ValueError('a not invertible, cannot solve'

Now suppose we have a matrix class (2x2 for simplicity and realism).
Its __bool__ (3.0) method implements 'is non-singular'. As written
above, solve(mat,vec) works (with compatible mat and vec sizes), but it
would not with 'if a != 0:'.

Of course, the issue goes away by not looking before the leap:

def solve(a,b):
return a/b
# let callers deal with exceptions
or
try:
return a/b
except...
# raise customized error

Maybe I'm going to be pedantic here, but I fear that your code won't
work with matrices. The problem is that multiplication is not
commutative with matrices. This means that matrices have two divisions a right
and a left division. A far as I know the "/" operator usaly implements
the left division while solving is done by using a right division.

So your code will probably fail when applied to matrices.
 
T

Terry Reedy

Erik said:
Antoon Pardon wrote: [responding to me]
Maybe I'm going to be pedantic here, but I fear that your code won't
work with matrices. The problem is that multiplication is not
commutative with matrices. This means that matrices have two divisions
a right
and a left division. A far as I know the "/" operator usaly implements
the left division while solving is done by using a right division.

So your code will probably fail when applied to matrices.

Your remarks are correct as far as they go, but..
You're right in your general point, but usually division between
matrices isn't defined at all because of this ambiguity. However the
general point can still exist between `solveLeft` and `solveRight`
functions which do something along the lines of a*b**-1 and a**-1*b. A
single `solve`, of course, would choose one of these, and syntactically
it might be quite reasonable to define matrix division that does one of
these and have a single `solve` function that accomplishes it.

Therefore, the general point about polymorphism still stands.

as Eric suggests, I was assuming that details would be defined to make
my example work. The context was the challenge to find an example
where, for instance, 'if x:' would work but something more specific like
'if x != 0:' would not. My abstract answer was "number-like class with
division that is not valid for the class's null object". The concrete
answer was an incomplete instantiation of that for matrices. Given the
critique, polynomial division might be a better example since polynomial
multiplication is commutative while both ()(if allowed) and (0,) as
polyomials might well be defined as != to numeric 0. I suspect there
are other algebra classes that work for this or other examples, but it
has been a loooooong time since I took abstract algebra.

Actually I sort of worked too hard ;-).
The decimal module breaks the transitivity of equality!
True

So if someone wrote 'if x == 0.0:' instead of 'if not x:' (perhaps to
raise an exception with explanation for unusable input), the former
would not work.

tjr
 

Ask a Question

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

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

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,534
Members
45,007
Latest member
obedient dusk

Latest Threads

Top