在 Python 3.x 中,将非 类 指定为基数 类 是否合法?

In Python 3.x, is it legal to specify non-classes as base classes?

这是一个例子:

>>> def magic(name, bases, dct):
...     print(repr(bases))
...     return type(name, (object,), dct)
... 
>>> class Foo('hello world!', metaclass=magic):
...     pass
... 
('hello world!',)
>>> Foo
<class '__main__.Foo'>
>>> Foo.__bases__
(<class 'object'>,)
>>> 

我对 class 语句特别感兴趣。虽然这看起来确实有效,但我无法在 language reference 中找到任何对此技术的具体认可。 "advanced uses" 语言可能是指使用关键字参数(例如 metaclass=),而不是位置参数。我想知道这是意外还是设计。

如果元类是 type 的子类,它确实会失败并显示一个相当有趣的 TypeError,如所讨论的 elsewhere in the reference:

>>> class Meta(type):
...     def __new__(mcs, name, bases, dct):
...         print(repr(bases))
...         bases = (object,)
...         return super().__new__(mcs, name, bases, dct)
...     def __init__(cls, name, bases, dct):
...         super().__init__(name, (object,), dct)
... 
>>> class Foo('hello world!', metaclass=Meta):
...     pass
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
>>>

总结一下:什么时候(如果有的话)将非类作为基数传递是合法的类?

您的问题表述有误:如果继承对象(基)不是 classes,它们就不是 'base classes'。关于复合语句的语言文档部分:class 说

The inheritance list usually gives a list of base classes

'Usually' 预计碱基不是 class 的可能性。话虽如此,该文档似乎继续假设碱基 classes 并且可以称为 'base classes'.

你的例子表明这种可能性是可以实现的。 "advanced uses" 上的数据模型:自定义 Class 创建部分(3.3.3 in 3.4)详细介绍了 class 语句的工作原理。相关步骤是第一步,确定metaclass,最后一步,调用metaclass.

我发现 3.3.3.1,"Determining the appropriate metaclass" 有点不清楚。第一条规则

if no bases and no explicit metaclass are given, then type() is used

不适用于您的任何一个示例。第二条规则

if an explicit metaclass is given and it is not an instance of type(), then it is used directly as the metaclass

似乎适用于您的第一个示例。但是我想知道 'instance' 应该是 'subclass' 还是 'instance or subclass'。否则,这似乎适用于您的第二个示例,但事实并非如此。第三条规则

if an instance of type() is given as the explicit metaclass, or bases are defined, then the most derived metaclass is used

必须包括 type() 的子classes 而不是(只是?)'instances',因为我们知道它已应用于您的第二个示例。第二个子句 ("or bases ..." 似乎适用于您的第一个示例,但我相信它不会。

当前对 class 创建的最终答案应该在类型对象 source 中。错误消息来自第 2265 行。