简体   繁体   中英

How to make a python instance inherit all of the behavior of one of its attributes?

Let's say I have a python class:

class A:
    baz = 1

    def bar(self, x):
        return self.baz * x

Now let's say I have a second class, keeps an instance of the first class as an attribute:

class B:
    def __init__(self, a, z):
        self.a = a
        self.z = z

    @property
    def baz(self):
        return z

Notice that B does not inherit from class A ; it's not even aware of it.

How can I make an instance of B act like an instance of A , except for the behavior explicitly given in the definition of B ? For example, if I want

a = A()
b = B(a, 2)
assert b.bar(2) == 4

that is, use A.bar but passing in b as self . To get this behavior, it's not enough to just do something like

class B:
    ...

    def getattr(self, attribute):
        return getattr(self.a, attribute)

That will allow any method not defined on self to be looked up on self.a . This works for constants and static methods, but for instance methods it's wrong, because b.bar would resolve to A.bar with self bound to ba .

Basically what I want to do is dynamically insert A (or more generally, whatever the type of a in B.__init__ is) into the MRO for that instance. In other words, to make B inherit from whatever the type of a is, on a per-instance basis.

Is such a thing possible?

A hackey way: you can do the method binding yourself in __getattr__ , note, all functions are descriptors, so they have a __get__ method!

In [47]: class A:
    ...:     baz = 1
    ...:
    ...:     def bar(self, x):
    ...:         return self.baz * x
    ...:
    ...:
    ...: class B:
    ...:     def __init__(self, a, z):
    ...:         self.a = a
    ...:         self.z = z
    ...:
    ...:     @property
    ...:     def baz(self):
    ...:         return self.z
    ...:
    ...:     def __getattr__(self, attribute):
    ...:         try:
    ...:             attr =  getattr(type(self.a), attribute)
    ...:         except AttributeError:
    ...:             return getattr(self.a, attribute)
    ...:
    ...:         if callable(attr):
    ...:             return attr.__get__(self)
    ...:         return attr
    ...:
    ...:
    ...:

In [48]: a = A()
    ...: b = B(a, 2)
    ...: b.bar(2)
    ...:
Out[48]: 4

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM