简体   繁体   中英

What happens when I inherit from an instance instead of a class in Python?

I'm just curious what will happen when I inherit an instance into a class.

So I tried:

class X:
    def __init__(self, x):
        self.x = x
    def print(self):
        print(self.x)

def inherit(obj):
    class Child(obj): # Line 20
        pass  # or maybe added functionality

    return Child

param = 5
x = X(param)
y = inherit(x) # Line 27
y.print()

I get (at least) the following error:

Traceback (most recent call last):
  File "/test.py", line 27, in <module>
    y = inherit(x)
  File "/test.py", line 20, in inherit
    class Child(obj):
TypeError: __init__() takes 2 positional arguments but 4 were given

I just wonder: Is inheriting an instance anything meaningful/useful or just plain nonsense?

(The question is a bit academic and specifically about the details of inheriting an instance. It's not about alternatives like object delegation or general design practices.)

Classes are just like instances; they have a type . For instances that type is the class, but for classes, the type is called a metaclass . Inheriting from a class normally would call the metatype of the base class to produce a new class object (using type(base) ; for multiple bases restrictions apply). The standard metatype is the type object, but you can create your own metaclasses .

By inheriting from an instance, Python tries to create a new class by calling type(obj)(classname, bases, body_namespace) . Since type(obj) is X and X.__init__() doesn't support those arguments, the call fails. However, there is nothing stopping you from making that part work!

>>> class X:
...     def __init__(self, classname, parents, namespace):
...         print('Creating {}{}'.format(classname, parents))
...
>>> class Child(X('X', (), {})): pass
...
Creating X()
Creating Child(<__main__.X object at 0x10372b4a8>,)
>>> Child
<__main__.X object at 0x10372b470>
>>> Child()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'X' object is not callable

Of course, type provides a lot more functionality that a class won't offer out of the box; there are a series of descriptors to provide attributes on a class that other parts of Python expect to exist. Your class would have to cover all of those instead; in the above sample output, you'll note that repr(Child) produces <__main__.X object at 0x...> rather than the expected <class '__main__.Child'> , and there is no __call__ method to produce instances for the class. So using an instance as a base class for another can work, you just have to put in the extra work to define all that expected functionality.

In the end, using an instance as a base class may be possible, but has no practical uses, not when any of the use-cases are already covered by metaclasses instead.

Python has, under the hood, a protoype-based model of object-oriented design. This means that everything, even classes, are objects in the Pythonic world. https://en.wikipedia.org/wiki/Prototype-based_programming

The relationship of inheritance in Python is carried out via a reference in the instance that signals its class. This is class . You can change this reference to any other class during runtime. If you do it to change the behaviour of the instance at runtime, then you are implementing dynamic inheritance. For example, think of an instance of a list of one element, the ListOfOne class, which has appropriate methods to deal with just one element. If another element was added, then the class reference could change to RegularList . If the list was emptied, then its class could change to EmptyList .

Unfortunately (or not) Python hides all of this. For example, you create your prototypes under the class label, and some operations that could be perfectly legal under this view are prohibited. Thus, it would be possible to inherit from an instance, but Python denies the possibility.

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