Subclassing complex with computed arguments
Bengt Richter
bokr at oz.net
Sat Nov 27 18:59:08 EST 2004
On 25 Nov 2004 14:30:18 -0800, pcolsen at comcast.net (Peter Olsen) wrote:
>I want to define a class "point" as a subclass of complex.
>
>When I create an instance
>
>sample = point(<arglist>)
>
>I want "sample" to "be" a complex number, but with its real and
>imaginary parts computed in point()'s __init__ function with their
>values based on the arglist. I want to compute with point instances
>as though they were native complex numbers, but I want to be able to
>define some new methods and over-ride some of complex's existing ones.
>
>This is probably very simple, but it hasn't been simple to me.
>
>Please feel free to flame me with RTFM as long as you also tell me
>where in TFM to R.
>
>If you respond, please send a copy directly to me. I seldom have
>access to this group. (My primary network isn't connected to the
>internet.)
>
Well, let us know how it goes, and maybe tell the curious what your
application is ;-). BTW, as others have explained, the initialization
of values is done via complex.__new__, not via __init__. You can override that
too, but I just let it be inherited to do its normal thing.
The following is a way to automate wrapping complex so as to return point instances
from the various operations. Not tested beyond what you see, and it won't
be a speed demon, but might be something to explore your concept with.
If you want to add special methods, you can do it like __repr__ and __coerce__
in the example, or you could add them after. Or you could use a proper metaclass
instead of doing it the function way.
Python 2.4b1 (#56, Nov 3 2004, 01:47:27)
[GCC 3.2.3 (mingw special 20030504-1)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> class point(complex):
... """complex wrapper subclass point"""
... def __metaclass__(cname, cbases, cdict):
... P = type(cname, cbases, cdict)
... def mkm(name, func):
... def m(*args): return P(func(*args))
... m.__name__ = name
... return m
... for name, func in complex.__dict__.items():
... if callable(func) and name not in ['__coerce__',
... '__doc__', '__float__', '__getattribute__', '__getnewargs__',
... '__hash__', '__int__', '__long__', '__new__', '__repr__',
... '__str__', 'imag', 'real']:
... setattr(P, name, mkm(name, func))
... def __coerce__(self, other): return self, P(other)
... P.__coerce__ = __coerce__
... def __repr__(self): return '<point %s>'% complex.__repr__(self)
... P.__repr__ = __repr__
... return P
...
>>> p = point(3, 4)
>>> p
<point (3+4j)>
>>> p+1
<point (4+4j)>
>>> p-1
<point (2+4j)>
>>> 1-p
<point (-2-4j)>
>>> 1+p
<point (4+4j)>
>>> p*p
<point (-7+24j)>
>>> p*p.conjugate()
<point (25+0j)>
>>> abs(p)
<point (5+0j)>
>>> print p, type(p), repr(p)
(3+4j) <class '__main__.point'> <point (3+4j)>
>>> p.imag
4.0
>>> p.real
3.0
You can explore further, and fix the bugs ;-)
I don't know what __getnewargs__ does, so I left it alone to be inherited.
Regards,
Bengt Richter
More information about the Python-list
mailing list