__coerce__ vs. new-style classes

  • Thread starter Hallvard B Furuseth
  • Start date
H

Hallvard B Furuseth

Why do new-style classes disable __coerce__()?
It seems cumbersome to have to write a whole set of methods (e.g.
__add__, __radd__, etc.) to get the same effect. Is there some way to
automatically generate those methods, or are we simply not supposed to
do coercion for some reason?
 
J

John Roth

Hallvard B Furuseth said:
Why do new-style classes disable __coerce__()?
It seems cumbersome to have to write a whole set of methods (e.g.
__add__, __radd__, etc.) to get the same effect. Is there some way to
automatically generate those methods, or are we simply not supposed to
do coercion for some reason?

I'm mildly confused by your example. __coerce__()
converts the arguements to a common type, and then
presumably requests that type to do the operation. That
type might not be one of the two original types!

It's not the same thing as the __op__, __rop__
pair. That simply allows the right object to do the
operation if the left object can't. (Also see 3.3.8
of the language reference for an exception to that
rule.)

The notion of type coercion makes a great deal of sense
in languages such as C, where you have 8 integer types
and 3 float types, but abstracting it out as a separate
operation makes very little sense in Python, where you
have 3 numeric types (int, long and float) and two string
types (normal and unicode). The overhead of doing
coercion as a separate operation simply doesn't make
a lot of sense.

At least, that's the way I understand it. Section 3.3.8
(Coercion Rules) of the 2.3 Language Reference gives
the official reasons for moving away from doing coercion
as part of operations. It simply got to complex to
document properly.

I suppose if you have a use case for __coerce__ in a
real world cluster of non-numeric types, you could
get Guido to reconsider.

John Roth
 
H

Hallvard B Furuseth

John said:
I'm mildly confused by your example. __coerce__()
converts the arguements to a common type, and then
presumably requests that type to do the operation. That
type might not be one of the two original types!

It's not the same thing as the __op__, __rop__
pair. That simply allows the right object to do the
operation if the left object can't.
Yes:
.... def __init__(self, fetch, *args, **kwargs):
.... def _fetch():
.... v = long(fetch(*args, **kwargs))
.... self.value = lambda: v
.... return v
.... self.value = _fetch
.... def __long__(self): return self.value()
.... def __int__(self): return int(self.value())
.... def __str__(self): return str(self.value())
.... def __coerce__(self, other):
.... if isinstance(other, (int, long)):
.... return type(other)(self.value()), other
.... 9

Can't add two of them without __add__ & co, but can do just about
everything else just by writing four small methods.

If I do include __add__ & co, they won't all have to coerce the
arguments 'by hand', or worry about what to do if they don't know
how to add the type of argument they received.

Without __coerce__, what should __add__(self, other) do if it doesn't
know how to add the arguments, but the other argument might know how?
It can't just call other.__radd__(self): That might give up and call
__add__ again.
In some cases it might help to call coerce() by hand, but I note the
ref manual says 'In Python 3.0, coercion will not be supported.'.
The notion of type coercion makes a great deal of sense
in languages such as C, where you have 8 integer types
and 3 float types, but abstracting it out as a separate
operation makes very little sense in Python, where you
have 3 numeric types (int, long and float) and two string
types (normal and unicode). The overhead of doing
coercion as a separate operation simply doesn't make
a lot of sense.

Well, I was thinking of types like the above, which emulate
numeric types. The case which got me started was one which
emulates the DECIMAL (or NUMERIC) SQL type in PgSQL.py.
At least, that's the way I understand it. Section 3.3.8
(Coercion Rules) of the 2.3 Language Reference gives
the official reasons for moving away from doing coercion
as part of operations. It simply got to complex to
document properly.

I noticed that; I hadn't realized it was the argument for disabling
coercion completey.
 
H

Hallvard B Furuseth

I said:
Without __coerce__, what should __add__(self, other) do if it doesn't
know how to add the arguments, but the other argument might know how?
It can't just call other.__radd__(self): That might give up and call
__add__ again.

Uh... please pretend I didn't say that.
You are right, I haven't gotten coerce() straight yet.
In some cases it might help to call coerce() by hand, but I note the
ref manual says 'In Python 3.0, coercion will not be supported.'.

Even so, coerce() by hand seems pretty cumbersome. The code I could
come up with for the general case is as follows. Am I missing something
again?

class Myclass(object):
def __add__(self, other):
if not isinstance(other, Myclass):
newself, other = coerce(self, other)
if newself != self:
return newself.__add__(other)
# Or maybe the above should test if
# newself.__class__ != self.__class__, and do
# self = newself if they have the same class.
...real __add__(Myclass, Myclass) starts here...
 

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
474,202
Messages
2,571,057
Members
47,666
Latest member
selsetu

Latest Threads

Top