【问题标题】:What does it mean for a class to inherit from an object which is not a type?类从非类型的对象继承意味着什么?
【发布时间】:2021-03-01 22:41:51
【问题描述】:

我在 Python 3.8 中遇到了一个奇怪的类继承案例。

我可以通过从一个本身不是type 的实例继承来创建一个类。在那种情况下,我预计会出现 TypeError,但事实并非如此。

class B:
    def __new__(cls, *args, **kwargs):
        print(args, kwargs)
        return super().__new__(cls)

b = B()  # prints: () {}

class A(b):  # I expected a TypeError here
    x = "foo"
# prints: ('A', (<__main__.B object at 0x7f32bd102390>,),
#         {'__module__': '__main__', '__qualname__': 'A', 'x': 'foo'}) {}

print(A)  # <__main__.B object at 0x7f20556c93d0>
print(isinstance(A, B))  # True
print(isinstance(A, type))  # False

看起来当我将B() 作为A 的基础时,然后B 被用作元类。

我的理解正确吗?为什么会这样?而且我似乎找不到任何关于这种行为的信息,它是记录在案的还是特定于 cPython 的实现怪癖?

【问题讨论】:

  • 好像在你的代码末尾调用A() sn-p raises TypeError: 'B' object is not callable
  • @JakeLevi 是的,这是因为 A 最终成为 B 的实例而不是类型......由于某些语义原因,我看不到。
  • 另外,如果我注释掉您对B 的定义并用class B: pass 替换它,那么class A(b): 行将引发TypeError: B() takes no arguments,正如您所料。因此,我猜您的问题的答案与 __new__ 特殊方法的行为有关,您可以在此处阅读更多信息:docs.python.org/3/reference/datamodel.html#object.__new__

标签: python python-3.x class inheritance metaclass


【解决方案1】:

基本上,类型构造函数将检查基数以猜测派生最多的元类。然后它将看到A 的实例,并将其类用作“最派生的元类”。所以,是的,“基础”中的事物类被用作元类。

从那时起,它将调用检索到的“元类”来构建 B 类本身。因为它是一个类,所以它被调用,这会像往常一样触发类'__new__。因为它返回一个“A”的实例,这就是你作为你的“B”得到的:Python 不会妨碍验证返回的元类可调用对象本身是否是一个“类”——它可以是任何对象。给定适当的超类或元类,这使人们可以灵活地滥用类语句来构建其他类型的对象。在这种情况下,它只是碰巧没有引发 TypeError 并返回一个“A”实例。 (但你必须调整类'__new__ 以避免 TypeError)


In [16]: class A: 
    ...:     def __new__(cls, *args, **kw): 
    ...:         print(args, kw) 
    ...:         return  super().__new__(cls) 
    ...:          
    ...:                

In [17]: class B(A()): pass                     
() {}
('B', (<__main__.A object at 0x7f26862395b0>,), {'__module__': '__main__', '__qualname__': 'B'}) {}

In [18]: type(B)        
Out[18]: __main__.A

In [19]: isinstance(B, A)                       
Out[19]: True

【讨论】:

  • 谢谢。这里的关键字实际上是“派生元类”。从那里我可以找到我需要的所有文档。
猜你喜欢
  • 2013-01-16
  • 2011-08-28
  • 2016-01-02
  • 2021-05-17
  • 2012-01-15
  • 1970-01-01
  • 1970-01-01
  • 2021-12-11
  • 2021-11-30
相关资源
最近更新 更多