classmethod() not inherited?

Andrew Bennetts andrew-pythonlist at puzzling.org
Thu Jan 16 05:24:17 EST 2003


On Thu, Jan 16, 2003 at 04:43:35AM -0500, Jack Diederich wrote:
> How is it possible to have classmethods still be
> classmethods in their kids?
> 
> -- file Test.py --
> class Base(object):
>   def foo(cls):
>     return 'BASE!'
>   foo = classmethod(foo)
> 
> class A(Base):
>   def foo(cls):
>     return 'some value'
> 
> class B(Base):
>   def foo(cls):
>     return 'some other value'
> 
> class Z(Base):
>   def foo(cls):
>     return 'something else still'
> 
> 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...

-Andrew.






More information about the Python-list mailing list