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