class MyInt(int):
def __add__(self, other):
return self.__class__(super(MyInt, self).__add__(other))
# and so on for __mul__, __sub__, etc.
My quick-and-dirty count of the __magic__ methods that need to be over-
ridden comes to about 30. That's a fair chunk of unexciting boilerplate.
Is there a trick or Pythonic idiom to make arithmetic operations on a
class return the same type, without having to manually specify each
method? I'm using Python 2.5, so anything related to ABCs are not an
option.
Does anyone have any suggestions?
--
Steven
Something like this maybe?
def takesOneArg(fn):
try:
fn(1)
except TypeError:
return False
else:
return True
class MyInt(int): pass
template = "MyInt.__%s__ = lambda self, other: self.__class__(super
(MyInt, self).__%s__(other))"
fns = [fn for fn in dir(int) if fn.startswith('__') and takesOneArg
(getattr(1,fn))]
print fns
for fn in fns:
exec(template % (fn,fn))
Little harm in this usage of exec, since it is your own code that you
are running.
-- Paul
I do this:
binops = ['add', 'sub', 'mul', 'div', 'radd', 'rsub'] # etc
unops = ['neg', 'abs', invert'] # etc
binop_meth = """
def __%s__(self, other):
return type(self)(int.__%s__(self, other))
"""
unop_meth = """
def __%s__(self):
return type(self)(int.__%s__(self))
"""
class MyInt(int):
for op in binops:
exec binop_meth % (op, op)
for op in unops:
exec unop_meth % (op, op)
del op
HTH
--
Arnaud
> binops = ['add', 'sub', 'mul', 'div', 'radd', 'rsub'] # etc
> unops = ['neg', 'abs', invert'] # etc
Oops. There's a missing quote above. It should have been, of course:
Just an idea:
def myint(meth):
def mymeth(*args):
return MyInt(meth(*args))
return mymeth
class MyIntMeta(type):
method_names = 'add sub mul neg'.split()
def __new__(cls, name, bases, attrs):
t = type.__new__(cls, name, bases, attrs)
for name in MyIntMeta.method_names:
name = '__%s__' % name
meth = getattr(t, name)
setattr(t, name, myint(meth))
return t
class MyInt(int):
__metaclass__ = MyIntMeta
a = MyInt(3)
b = MyInt(3000)
print a
print b
c = a + b
print c
assert isinstance(c, MyInt)
d = c * MyInt(4)
print d
e = c * 6 * a * b
print e
assert isinstance(e, MyInt)
x = -e
print x
assert isinstance(x, MyInt)
what's the "del" for?
curious,
andrew
To not pollute the namespace of MyInt - otherwise, you could do
MyInt(10).op
Diez
Without it, 'op' would end up as a class attribute.
> curious,
> andrew
--
Arnaud
ah! ok, that makes sense, i guess. thanks.
(i just tried it out and you're right, of course, but also if binops and
unops are empty you get an error, although i guess that's no an issue
here).
andrew
Metaclasses can be used for this purpuse, see the example for a Roman number
type [1]
[1] http://paste.pocoo.org/show/97258/
--
Freedom is always the freedom of dissenters.
(Rosa Luxemburg)
(syntax not necessarily correct, but you get the idea)
Run redirected to lib or program source.
Steve
>> Is there a trick or Pythonic idiom to make arithmetic operations on a
>> class return the same type, without having to manually specify each
>> method? I'm using Python 2.5, so anything related to ABCs are not an
>> option.
>>
>> Does anyone have any suggestions?
>
> Metaclasses can be used for this purpuse, see the example for a Roman
> number type [1]
>
> [1] http://paste.pocoo.org/show/97258/
That's an interesting solution. I like it.
Thanks to all who responded, I see that there's no best practice to get
what I want, so I'll do some experimentation.
--
Steven
class MyInt(int):
def __getattribute__(self, key):
if key == "__add__":
print("In __getattribute__('__add__')")
return lambda other: MyInt(int.__add__(self, other+100))
else:
return object.__getattribute__(self, key)
def __getattr__(self, key):
if key == "__add__":
print("In __getattr__('__add__')")
return lambda other: MyInt(int.__add__(self, other+100))
else:
return object.__getattr__(self, key)
I then do this:
>>> a = MyInt(4)
>>> a.__add__(2)
In __getattribute__('__add__')
106
>>> a + 2
6
>>>
Why doesn't "a + 2" look up the __add__ attribute and use my lambda?
If I manually define __add__(self, other) then "a + 2" will of course
use that method.
Michael
>M> While thinking about Steven D'Aprano's thread about automatically
>M> generating arithmetic operations for a subclass, I stumbled upon
>M> something confusing. Having defined the following class to do funky
>M> addition,
>M> class MyInt(int):
>M> def __getattribute__(self, key):
>M> if key == "__add__":
>M> print("In __getattribute__('__add__')")
>M> return lambda other: MyInt(int.__add__(self, other+100))
>M> else:
>M> return object.__getattribute__(self, key)
>M> def __getattr__(self, key):
>M> if key == "__add__":
>M> print("In __getattr__('__add__')")
>M> return lambda other: MyInt(int.__add__(self, other+100))
>M> else:
>M> return object.__getattr__(self, key)
>M> I then do this:
>>>>> a = MyInt(4)
>>>>> a.__add__(2)
>M> In __getattribute__('__add__')
>M> 106
>>>>> a + 2
>M> 6
>>>>>
>M> Why doesn't "a + 2" look up the __add__ attribute and use my lambda?
>M> If I manually define __add__(self, other) then "a + 2" will of course
>M> use that method.
This has just been discussed in the thread "Overriding methods
per-object". In short: In newstyle classes these methods when invoked
implicitely, e.g by a+2, are only looked up in the class, and bypass
__getattribute__.
See http://docs.python.org/reference/datamodel.html#special-method-lookup-for-new-style-classes
--
Piet van Oostrum <pi...@cs.uu.nl>
URL: http://pietvanoostrum.com [PGP 8DAE142BE17999C4]
Private email: pi...@vanoostrum.org
Answer 1: because it was not programmed that way ;-).
Answer 2: because __getattribute__/__getattr__ are for looking up
attributes of instances of the class, whereas special methods are
generally required to be attributes of the class. So *their* lookup
would use type(MyInt).__getxxx__. When that fails, the add code looks
for int.__radd__. (I *think* this your answer.)
> If I manually define __add__(self, other) then "a + 2" will of course
> use that method.
because that is that type(MyInt).__getxxx__ will find.
tjr