gog
gog

Reputation: 11347

Refer to a superclass from the class body

I've got some code where I need to refer to a superclass when defining stuff in a derived class:

class Base:
    def foo(self):
        print('foo')

    def bar(self):
        print('bar')


class Derived_A(Base):
    meth = Base.foo


class Derived_B(Base):
    meth = Base.bar


Derived_A().meth()
Derived_B().meth()

This works, but I don't like verbatim references to Base in derived classes. Is there a way to use super or alike for this?

Upvotes: 2

Views: 78

Answers (4)

S.B
S.B

Reputation: 16476

You can't do that.

class keyword in Python is used to create classes which are instances of type type. In it's simplified version, it does the following:

  1. Python creates a namespace and executes the body of the class in that namespace so that it will be populated with all methods and attributes and so on...

  2. Then calls the three-arguments form of type(). The result of this call is your class which is then assign to a symbol which is the name of your class.

The point is when the body of the class is being executed. It doesn't know about the "bases". Those bases are passed to the type() after that.

I also explained the reasons why you can't use super() here.

Upvotes: 1

Dillon Davis
Dillon Davis

Reputation: 7740

Since you want "magic", there is still one sane option we can take before diving into metaclasses. Requires Python 3.9+

def alias(name):
    def inner(cls):
        return getattr(cls, name).__get__(cls)
    return classmethod(property(inner))

class Base:
    def foo(self):
        ...

class Derived_A(Base):
    meth = alias("foo")

Derived_A().meth()  # works
Derived_A.meth()  # also works

Yes, this does require passing the method name as a string, which destroys your IDE and typechecker's ability to reason about it. But there isn't a good way to get what you are wanting without some compromises like that.

Really, a bit of redundancy for readability is probably worth it here.

Upvotes: 0

Dillon Davis
Dillon Davis

Reputation: 7740

You'll need to lookup the method on the base class after the new type is created. In the body of the class definition, the type and base classes are not accessible.

Something like:

class Derived_A(Base):
    def meth(self):
        return super().foo()

Now, it is possible to do some magic behind the scenes to expose Base to the scope of the class definition as its being executed, but that's much dirtier, and would mean that you'd need to supply a metaclass in your class definition.

Upvotes: 0

YD9
YD9

Reputation: 555

Does this work for you?

class Base:
    def foo(self):
        print('foo')

    def bar(self):
        print('bar')


class Derived_A(Base):
    def __init__(self):
        self.meth = super().foo

class Derived_B(Base):
    def __init__(self):
        self.meth = super().bar


a = Derived_A().meth()
b = Derived_B().meth()

Upvotes: 0

Related Questions