关于你的第一个问题,元类应该是MyMetaclass(就是这样):
In [7]: print(type(MyClass), type(MyDerived))
原因是,如果元类不是python类型的实例,则通过将这些参数传递给它来调用methaclass name,bases,ns,** kwds(请参阅new_class)并且因为你在该函数中返回真正的元类,它会得到元类的正确类型.
关于第二个问题:
What is the purpose of accepting an arbitrary callable?
没有特殊目的,它实际上是元类的本质,因为从类中创建实例总是通过调用它的__call__方法来调用元类:
Metaclass.__call__()
这意味着你可以传递任何可调用的元类作为你的元类.因此,例如,如果使用嵌套函数对其进行测试,结果仍将是相同的:
In [21]: def metaclass_callable(name, bases, namespace):
def inner():
return MyMetaclass(name, bases, namespace)
return inner()
....:
In [22]: class MyClass(metaclass=metaclass_callable):
pass
....:
In [23]: print(type(MyClass), type(MyDerived))
有关更多信息,请参阅Python如何创建类:
它调用new_class函数,它在其自身内部调用prepare_class,然后你可以在prepare_class中看到python调用相应元类的__prepare__方法,除了找到正确的元(使用_calculate_meta函数)并为类创建适当的命名空间.
所以这里所有的都是执行metacalss方法的层次结构:
> __prepare__ 1
> __call__
> __new__
> __init__
这是源代码:
# Provide a PEP 3115 compliant mechanism for class creation
def new_class(name, bases=(), kwds=None, exec_body=None):
"""Create a class object dynamically using the appropriate metaclass."""
meta, ns, kwds = prepare_class(name, bases, kwds)
if exec_body is not None:
exec_body(ns)
return meta(name, bases, ns, **kwds)
def prepare_class(name, bases=(), kwds=None):
"""Call the __prepare__ method of the appropriate metaclass.
Returns (metaclass, namespace, kwds) as a 3-tuple
*metaclass* is the appropriate metaclass
*namespace* is the prepared class namespace
*kwds* is an updated copy of the passed in kwds argument with any
'metaclass' entry removed. If no kwds argument is passed in, this will
be an empty dict.
"""
if kwds is None:
kwds = {}
else:
kwds = dict(kwds) # Don't alter the provided mapping
if 'metaclass' in kwds:
meta = kwds.pop('metaclass')
else:
if bases:
meta = type(bases[0])
else:
meta = type
if isinstance(meta, type):
# when meta is a type, we first determine the most-derived metaclass
# instead of invoking the initial candidate directly
meta = _calculate_meta(meta, bases)
if hasattr(meta, '__prepare__'):
ns = meta.__prepare__(name, bases, **kwds)
else:
ns = {}
return meta, ns, kwds
def _calculate_meta(meta, bases):
"""Calculate the most derived metaclass."""
winner = meta
for base in bases:
base_meta = type(base)
if issubclass(winner, base_meta):
continue
if issubclass(base_meta, winner):
winner = base_meta
continue
# else:
raise TypeError("metaclass conflict: "
"the metaclass of a derived class "
"must be a (non-strict) subclass "
"of the metaclasses of all its bases")
return winner
1.请注意,它会在new_class函数内部和返回之前隐式调用.