问题描述
我想问一下with_metaclass()
调用在类的定义中是什么意思.
I want to ask what the with_metaclass()
call means in the definition of a class.
例如:
class Foo(with_metaclass(Cls1, Cls2)):
- 类是从元类继承的特殊情况吗?
- 新类也是元类吗?
推荐答案
with_metaclass()
是 six
库提供的实用程序类工厂函数,以简化为两个Python 2开发代码的过程和3.
with_metaclass()
is a utility class factory function provided by the six
library to make it easier to develop code for both Python 2 and 3.
使用一个临时元类需要一点点的手(见下文),以一种与Python 2和Python 3交叉兼容的方式将元类附加到常规类.
It uses a little slight of hand (see below) with a temporary metaclass, to attach a metaclass to a regular class in a way that's cross-compatible with both Python 2 and Python 3.
从文档中引用:
from six import with_metaclass
class Meta(type):
pass
class Base(object):
pass
class MyClass(with_metaclass(Meta, Base)):
pass
这是必需的,因为附加元类的语法在Python 2和3之间已更改.
This is needed because the syntax to attach a metaclass changed between Python 2 and 3:
Python 2:
class MyClass(object):
__metaclass__ = Meta
Python 3:
class MyClass(metaclass=Meta):
pass
with_metaclass()
函数利用以下事实:元类是a)由子类继承的,并且b)元类可用于生成新类,并且c)当您从具有元类的基类中子类化时,创建了实际的子类对象被委托给元类.它有效地创建了带有临时metaclass
元类的新的临时基类,当用于创建子类交换临时基类和元类组合以及您选择的元类时,
The with_metaclass()
function makes use of the fact that metaclasses are a) inherited by subclasses, and b) a metaclass can be used to generate new classes and c) when you subclass from a base class with a metaclass, creating the actual subclass object is delegated to the metaclass. It effectively creates a new, temporary base class with a temporary metaclass
metaclass that, when used to create the subclass swaps out the temporary base class and metaclass combo with the metaclass of your choice:
def with_metaclass(meta, *bases):
"""Create a base class with a metaclass."""
# This requires a bit of explanation: the basic idea is to make a dummy
# metaclass for one level of class instantiation that replaces itself with
# the actual metaclass.
class metaclass(type):
def __new__(cls, name, this_bases, d):
return meta(name, bases, d)
@classmethod
def __prepare__(cls, name, this_bases):
return meta.__prepare__(name, bases)
return type.__new__(metaclass, 'temporary_class', (), {})
打破以上:
-
type.__new__(metaclass, 'temporary_class', (), {})
使用metaclass
元类创建一个名为temporary_class
的新类对象,否则该对象将完全为空.使用type.__new__(metaclass, ...)
代替metaclass(...)
可以避免使用特殊的metaclass.__new__()
实现,以便在下一步工作时稍作努力. - 仅在Python 3中,当将
temporary_class
用作基类时,Python会首先调用metaclass.__prepare__()
(将派生的类名称(temporary_class,)
作为this_bases
参数传入.意图然后,使用em>元类meta
调用meta.__prepare__()
,忽略this_bases
并传入bases
参数. - 接下来,在将
metaclass.__prepare__()
的返回值用作类属性的基本名称空间之后(或在Python 2上仅使用普通字典)之后,Python调用metaclass.__new__()
来创建实际的类.再次将它作为this_bases
元组传递给(temporary_class,)
,但是上面的代码忽略了它,而是使用bases
来调用meta(name, bases, d)
来创建新的派生类.
type.__new__(metaclass, 'temporary_class', (), {})
uses themetaclass
metaclass to create a new class object namedtemporary_class
that is entirely empty otherwise.type.__new__(metaclass, ...)
is used instead ofmetaclass(...)
to avoid using the specialmetaclass.__new__()
implementation that is needed for the slight of hand in a next step to work.- In Python 3 only, when
temporary_class
is used as a base class, Python first callsmetaclass.__prepare__()
(passing in the derived class name,(temporary_class,)
as thethis_bases
argument. The intended metaclassmeta
is then used to callmeta.__prepare__()
, ignoringthis_bases
and passing in thebases
argument. - next, after using the return value of
metaclass.__prepare__()
as the base namespace for the class attributes (or just using a plain dictionary when on Python 2), Python callsmetaclass.__new__()
to create the actual class. This is again passed(temporary_class,)
as thethis_bases
tuple, but the code above ignores this and usesbases
instead, calling onmeta(name, bases, d)
to create the new derived class.
因此,使用with_metaclass()
将为您提供一个新的类对象,而没有其他基类:
As a result, using with_metaclass()
gives you a new class object with no additional base classes:
>>> class FooMeta(type): pass
...
>>> with_metaclass(FooMeta) # returns a temporary_class object
<class '__main__.temporary_class'>
>>> type(with_metaclass(FooMeta)) # which has a custom metaclass
<class '__main__.metaclass'>
>>> class Foo(with_metaclass(FooMeta)): pass
...
>>> Foo.__mro__ # no extra base classes
(<class '__main__.Foo'>, <type 'object'>)
>>> type(Foo) # correct metaclass
<class '__main__.FooMeta'>
这篇关于Python元类:了解"with_metaclass()"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!