Borrowing class method from another class (Python 3)

Borrowing the implementation of an instance method from another class is straightforward, but how do I do it with a class method?

class A:
  def im(self):
    print(self.__class__.__name__)

  @classmethod
  def cm(cls):
    print(cls.__name__)

class B:
  im = A.im
  cm = A.cm # line X
  classmethod(cm)

B().im() # B - OK
B.cm() # A - not what I want

I also tried changing line X into cm = A.cm.__func__, which caused TypeError: cm() missing 1 required positional argument: 'cls'

Upvotes: 1

Views: 1051

Answers (2)

Martijn Pieters
Martijn Pieters

Reputation: 1121486

When you access A.cm, you invoke the classmethod object as a descriptor, which means it is already bound to the A class. Unwrap it again:

class B:
    cm = classmethod(A.cm.__func__)

The .__func__ attribute gives you access to the original function, so you can rewrap it with a new classmethod call.

Alternatively, use the A.__dict__ mapping to get the actual classmethod itself, bypassing the descriptor calls:

class B:
    cm = A.__dict__['cm']

Upvotes: 4

BrenBarn
BrenBarn

Reputation: 251355

You need:

class B:
  im = A.im
  cm = classmethod(A.cm.__func__)

When you access A.cm, the resulting classmethod already "knows" that it belongs to A. If you want to rewrap it for a different class, you need to extract the underlying function with __func__ and then rewrap it with classmethod.

Also, in your example, the line classmethod(cm) does nothing, because you don't assign the result to anything.

Upvotes: 3

Related Questions