classmethod() not inherited?
Jacob Smullyan
smulloni at smullyan.org
Fri Jan 17 22:12:00 EST 2003
In article <mailman.1042712132.3419.python-list at python.org>, Andrew Bennetts wrote:
> On Thu, Jan 16, 2003 at 04:43:35AM -0500, Jack Diederich wrote:
>> I'd like to have ALL of the derivitives of Base
>> have foo as a classmethod, but it doesn't seem
>> to be automatic and the following doesn't work
> Well, foo *is* a classmethod in the derived classes -- it's just that you're
> replacing it with a foo that's not a classmethod <wink>.
>
> If you really want this, you could write a metaclass:
>
> ---
> class M(type):
> def __init__(cls, name, bases, dict):
> type.__init__(cls, name, bases, dict)
> if callable(dict.get('foo')):
> setattr(cls, 'foo', classmethod(dict['foo']))
>
> class Base(object):
> __metaclass__ = M # removing this line gives the old behaviour
> def foo(cls):
> return 'BASE!', cls
>
> # ... A, B and Z as before ...
>
> for x in (Base(), A(), B(), Z()):
> print x.foo()
> ---
>
> This will print:
> ('BASE!', <class '__main__.Base'>)
> ('some value', <class '__main__.A'>)
> ('some other value', <class '__main__.B'>)
> ('something else still', <class '__main__.Z'>)
>
> Instead of:
> ('BASE!', <__main__.Base object at 0x8121a6c>)
> ('some value', <__main__.A object at 0x81141d4>)
> ('some other value', <__main__.B object at 0x811345c>)
> ('something else still', <__main__.Z object at 0x814c644>)
>
> Of course, extending it to do this to all overridden classmethods, instead
> of being hard-coded to 'foo', is a little trickier, but not much...
>
For instance, the below uses a naming convention so the metaclass can
to determine which methods are class methods, and then classmethod-ify
them. Static methods are thrown in for good measure:
class _classymeta(type):
def __new__(self, cl_name, bases, namespace):
prefix_descriptor_pairs=(('static_', staticmethod),
('class_', classmethod))
for k, v in namespace.items():
for prefix, descriptor in prefix_descriptor_pairs:
lenpre=len(prefix)
if k.startswith(prefix):
methname=k[lenpre:]
if methname in namespace:
raise ValueError, \
"duplicate member name: %s" % methname
namespace[methname]=descriptor(v)
del namespace[k]
return type.__new__(self, cl_name, bases, namespace)
class thing(object):
__metaclass__=_classymeta
def static_foo(x, y):
print x, y
def class_foo2(k, x, y):
print k, x, y
class derivedthing(thing):
def class_foo2(k, x, y):
thing.foo2(x, y)
print "in foo2"
t=thing()
t.foo(1, 2)
t.foo2(1, 2)
v=derivedthing()
v.foo2(1, 2)
More information about the Python-list
mailing list