python元类_Python元类

python元类

The term metaprogramming refers to the potential for a program to have knowledge of or manipulate itself. Python supports a form of metaprogramming for classes called metaclasses.

术语元编程是指程序具有了解或操纵自身的潜力。 Python支持一种称为metaclasses的类的元编程形式。

Metaclasses are an esoteric OOP concept, lurking behind virtually all Python code. You are using them whether you are aware of it or not. For the most part, you don’t need to be aware of it. Most Python programmers rarely, if ever, have to think about metaclasses.

元类是一个深奥的OOP概念 ,几乎隐藏在所有Python代码之后。 无论您是否知道,都在使用它们。 在大多数情况下,您无需意识到这一点。 大多数Python程序员很少(即使有的话)也不必考虑元类。

When the need arises, however, Python provides a capability that not all object-oriented languages support: you can get under the hood and define custom metaclasses. The use of custom metaclasses is somewhat controversial, as suggested by the following quote from Tim Peters, the Python guru who authored the Zen of Python:

但是,当需要时,Python提供了并非所有面向对象的语言都支持的功能:您可以深入了解并定义自定义元类。 自定义元类的使用引起了一些争议,正如以下撰写蒂姆·彼得斯(Tim Peters)的话所暗示的那样:蒂姆·彼得斯(Tim Peters)是编写PythonZen的作者

“Metaclasses are deeper magic than 99% of users should ever worry about. If you wonder whether you need them, you don’t (the people who actually need them know with certainty that they need them, and don’t need an explanation about why).”

“元类是比99%的用户应该担心的更深的魔力。 如果您想知道是否需要它们,则不需要(实际上需要它们的人肯定会知道他们需要它们,并且不需要解释原因)。”

— Tim Peters

—蒂姆·彼得斯

There are Pythonistas (as Python aficionados are known) who believe that you should never use custom metaclasses. That might be going a bit far, but it is probably true that custom metaclasses mostly aren’t necessary. If it isn’t pretty obvious that a problem calls for them, then it will probably be cleaner and more readable if solved in a simpler way.

有一些Pythonista使用者(众所周知的Python爱好者)认为您永远不要使用自定义元类。 这可能会有点远,但是很可能不需要自定义元类。 如果不是很明显有问题需要解决这些问题,那么如果以更简单的方式解决问题,它可能会更干净,更易读。

Still, understanding Python metaclasses is worthwhile, because it leads to a better understanding of the internals of Python classes in general. You never know: you may one day find yourself in one of those situations where you just know that a custom metaclass is what you want.

尽管如此,理解Python元类还是值得的,因为它通常可以更好地理解Python类的内部。 您永远不会知道:有一天您可能会遇到一种情况,即您只知道自定义元类就是您想要的。

Get Notified: Don’t miss the follow up to this tutorial—Click here to join the Real Python Newsletter and you’ll know when the next instalment comes out.

通知您:不要错过本教程的后续内容- 单击此处加入Real Python Newslet ,您将知道下一期的发行时间。

旧式与新式类 (Old-Style vs. New-Style Classes)

In the Python realm, a class can be one of two varieties. No official terminology has been decided on, so they are informally referred to as old-style and new-style classes.

在Python领域中,类可以是两个变体之一 。 尚未确定官方术语,因此将它们非正式地称为旧类和新类。

旧式类 (Old-Style Classes)

With old-style classes, class and type are not quite the same thing. An instance of an old-style class is always implemented from a single built-in type called instance. If obj is an instance of an old-style class, obj.__class__ designates the class, but type(obj) is always instance. The following example is taken from Python 2.7:

对于老式的类,类和类型不是一回事。 旧式类的实例始终由称为instance的单个内置类型实现。 如果obj是旧类的实例,则obj.__class__指定该类,但type(obj)始终是instance 。 以下示例取自Python 2.7:

 >>> >>>  class class FooFoo :
:
...     ...     pass
pass
...
...
>>> >>>  x x = = FooFoo ()
()
>>> >>>  xx .. __class__
__class__
<class __main__.Foo at 0x000000000535CC48>
<class __main__.Foo at 0x000000000535CC48>
>>> >>>  typetype (( xx )
)
<type 'instance'>
<type 'instance'>

新型类 (New-Style Classes)

New-style classes unify the concepts of class and type. If obj is an instance of a new-style class, type(obj) is the same as obj.__class__:

新型类统一了类和类型的概念。 如果obj是新样式类的实例,则type(obj)obj.__class__相同:

 >>> >>>  n n = = 5
5
>>> >>>  d d = = { { 'x' 'x' : : 11 , , 'y' 'y' : : 2 2 }

}

>>> >>>  class class FooFoo :
:
...     ...     pass
pass
...
...
>>> >>>  x x = = FooFoo ()

()

>>> >>>  for for obj obj in in (( nn , , dd , , xx ):
):
...     ...     printprint (( typetype (( objobj ) ) is is objobj .. __class____class__ )
)
...
...
True
True
True
True
True
True

类型和类别 (Type and Class)

In Python 3, all classes are new-style classes. Thus, in Python 3 it is reasonable to refer to an object’s type and its class interchangeably.

在Python 3中,所有类都是新型类。 因此,在Python 3中,可以互换地引用对象的类型及其类是合理的。

Note: In Python 2, classes are old-style by default. Prior to Python 2.2, new-style classes weren’t supported at all. From Python 2.2 onward, they can be created but must be explicitly declared as new-style.

注意:在Python 2中,默认情况下,类为旧样式。 在Python 2.2之前,根本不支持新型类。 从Python 2.2开始,可以创建它们,但必须将其显式声明为new-style。

Remember that, in Python, everything is an object. Classes are objects as well. As a result, a class must have a type. What is the type of a class?

请记住, 在Python中,一切都是对象。 类也是对象。 结果,一个类必须具有一个类型。 什么是课程类型?

Consider the following:

考虑以下:

The type of x is class Foo, as you would expect. But the type of Foo, the class itself, is type. In general, the type of any new-style class is type.

如您所料, x的类型为Foo类。 但是Foo的类型(类本身)是type 。 通常,任何新式类的type都是type

The type of the built-in classes you are familiar with is also type:

您熟悉的内置类的typetype

 >>> >>>  for for t t in in intint , , floatfloat , , dictdict , , listlist , , tupletuple :
:
...     ...     printprint (( typetype (( tt ))
))
...
...
<class 'type'>
<class 'type'>
<class 'type'>
<class 'type'>
<class 'type'>
<class 'type'>
<class 'type'>
<class 'type'>
<class 'type'>
<class 'type'>

For that matter, the type of type is type as well (yes, really):

因此,类型的type也是type (是的,是的):

type is a metaclass, of which classes are instances. Just as an ordinary object is an instance of a class, any new-style class in Python, and thus any class in Python 3, is an instance of the type metaclass.

type是一个元类,其中的类是实例。 就像普通对象是类的实例一样,Python中的任何新式类以及Python 3中的任何类都是元类type实例。

In the above case:

在上述情况下:

  • x is an instance of class Foo.
  • Foo is an instance of the type metaclass.
  • type is also an instance of the type metaclass, so it is an instance of itself.
  • xFoo类的实例。
  • Footype元类的实例。
  • type也是type元类的实例,因此它也是其自身的实例。

class chain

动态定义类 (Defining a Class Dynamically)

The built-in type() function, when passed one argument, returns the type of an object. For new-style classes, that is generally the same as the object’s __class__ attribute:

当传递一个参数时,内置的type()函数将返回对象的类型。 对于新型类,通常与对象的__class__属性相同

 >>> >>>  typetype (( 33 )
)
<class 'int'>

<class 'int'>

>>> >>>  typetype ([([ 'foo''foo' , , 'bar''bar' , , 'baz''baz' ])
])
<class 'list'>

<class 'list'>

>>> >>>  t t = = (( 11 , , 22 , , 33 , , 44 , , 55 )
)
>>> >>>  typetype (( tt )
)
<class 'tuple'>

<class 'tuple'>

>>> >>>  class class FooFoo :
:
...     ...     pass
pass
...
...
>>> >>>  typetype (( FooFoo ())
())
<class '__main__.Foo'>
<class '__main__.Foo'>

You can also call type() with three arguments—type(<name>, <bases>, <dct>):

您还可以使用三个参数调用type() type(<name>, <bases>, <dct>)

  • <name> specifies the class name. This becomes the __name__ attribute of the class.
  • <bases> specifies a tuple of the base classes from which the class inherits. This becomes the __bases__ attribute of the class.
  • <dct> specifies a namespace dictionary containing definitions for the class body. This becomes the __dict__ attribute of the class.
  • <name>指定类名称。 这将成为__name__属性。
  • <bases>指定从其继承的基类的元组。 这成为__bases__属性。
  • <dct>指定一个包含类主体定义的名称空间字典。 这成为该类的__dict__属性。

Calling type() in this manner creates a new instance of the type metaclass. In other words, it dynamically creates a new class.

以这种方式调用type()会创建type元类的新实例。 换句话说,它动态创建一个新类。

In each of the following examples, the top snippet defines a class dynamically with type(), while the snippet below it defines the class the usual way, with the class statement. In each case, the two snippets are functionally equivalent.

在以下每个示例中,最上面的代码段使用type()动态定义一个类,而其下面的代码段则使用class语句以通常的方式定义class 。 在每种情况下,这两个代码段在功能上是等效的。

例子1 (Example 1)

In this first example, the <bases> and <dct> arguments passed to type() are both empty. No inheritance from any parent class is specified, and nothing is initially placed in the namespace dictionary. This is the simplest class definition possible:

在第一个示例中,传递给type()<bases><dct>参数均为空。 没有指定任何父类的继承,并且最初在命名空间字典中未放置任何内容。 这是可能的最简单的类定义:

 >>> >>>  class class FooFoo :
:
...     ...     pass
pass
...
...
>>> >>>  x x = = FooFoo ()
()
>>> >>>  x
x
<__main__.Foo object at 0x0370AD50>
<__main__.Foo object at 0x0370AD50>

例子2 (Example 2)

Here, <bases> is a tuple with a single element Foo, specifying the parent class that Bar inherits from. An attribute, attr, is initially placed into the namespace dictionary:

在这里, <bases>是具有单个元素Foo的元组,指定Bar继承自的父类。 属性attr最初放置在名称空间字典中:

 >>> >>>  class class BarBar (( FooFoo ):
):
...     ...     attr attr = = 100
100
...

...

>>> >>>  x x = = BarBar ()
()
>>> >>>  xx .. attr
attr
100
100
>>> >>>  xx .. __class__
__class__
<class '__main__.Bar'>
<class '__main__.Bar'>
>>> >>>  xx .. __class____class__ .. __bases__
__bases__
(<class '__main__.Foo'>,)
(<class '__main__.Foo'>,)

例子3 (Example 3)

This time, <bases> is again empty. Two objects are placed into the namespace dictionary via the <dct> argument. The first is an attribute named attr and the second a function named attr_val, which becomes a method of the defined class:

这次, <bases>再次为空。 通过<dct>参数将两个对象放入名称空间字典中。 第一个是名为attr ,第二个是名为attr_val的函数,该函数成为已定义类的方法:

 >>> >>>  class class FooFoo :
:
...     ...     attr attr = = 100
100
...     ...     def def attr_valattr_val (( selfself ):
):
...         ...         return return selfself .. attr
attr
...

...

>>> >>>  x x = = FooFoo ()
()
>>> >>>  xx .. attr
attr
100
100
>>> >>>  xx .. attr_valattr_val ()
()
100
100

例子4 (Example 4)

Only very simple functions can be defined with lambda in Python. In the following example, a slightly more complex function is defined externally then assigned to attr_val in the namespace dictionary via the name f:

在Python中,只能使用lambda定义非常简单的函数。 在以下示例中,在外部定义了一个稍微复杂一点的函数,然后通过名称f将其分配给命名空间字典中的attr_val

 >>> >>>  def def ff (( objobj ):
):
...     ...     printprint (( 'attr =''attr =' , , objobj .. attrattr )
)
...
...
>>> >>>  class class FooFoo :
:
...     ...     attr attr = = 100
100
...     ...     attr_val attr_val = = f
f
...

...

>>> >>>  x x = = FooFoo ()
()
>>> >>>  xx .. attr
attr
100
100
>>> >>>  xx .. attr_valattr_val ()
()
attr = 100
attr = 100

自定义元类 (Custom Metaclasses)

Consider again this well-worn example:

再次考虑这个陈旧的示例:

The expression Foo() creates a new instance of class Foo. When the interpreter encounters Foo(), the following occurs:

表达式Foo()创建类Foo的新实例。 当解释器遇到Foo() ,将发生以下情况:

  • The __call__() method of Foo’s parent class is called. Since Foo is a standard new-style class, its parent class is the type metaclass, so type’s __call__() method is invoked.

  • That __call__() method in turn invokes the following:

    • __new__()
    • __init__()
  • Foo的父类的__call__()方法被调用。 由于Foo是标准的新型类,因此其父类是type元类,因此将调用type__call__()方法。

  • __call__()方法依次调用以下内容:

    • __new__()
    • __init__()

If Foo does not define __new__() and __init__(), default methods are inherited from Foo’s ancestry. But if Foo does define these methods, they override those from the ancestry, which allows for customized behavior when instantiating Foo.

如果Foo没有定义__new__()__init__() ,则默认方法将继承自Foo的祖先。 但是,如果Foo确实定义了这些方法,则它们会覆盖祖先中的方法,从而在实例化Foo时允许自定义行为。

In the following, a custom method called new() is defined and assigned as the __new__() method for Foo:

在下面,定义了一个名为new()的自定义方法,并将其分配为Foo__new__()方法:

 >>> >>>  def def newnew (( clscls ):
):
...     ...     x x = = objectobject .. __new____new__ (( clscls )
)
...     ...     xx .. attr attr = = 100
100
...     ...     return return x
x
...
...
>>> >>>  FooFoo .. __new__ __new__ = = new

new

>>> >>>  f f = = FooFoo ()
()
>>> >>>  ff .. attr
attr
100

100

>>> >>>  g g = = FooFoo ()
()
>>> >>>  gg .. attr
attr
100
100

This modifies the instantiation behavior of class Foo: each time an instance of Foo is created, by default it is initialized with an attribute called attr, which has a value of 100. (Code like this would more usually appear in the __init__() method and not typically in __new__(). This example is contrived for demonstration purposes.)

这会修改类Foo的实例化行为:每次创建Foo实例时,默认情况下都会使用名为attr的属性对其进行初始化,该属性的值为100 。 (这样的代码通常会出现在__init__()方法中,而不是通常出现在__new__() 。这个示例是为演示目的而设计的。)

Now, as has already been reiterated, classes are objects too. Suppose you wanted to similarly customize instantiation behavior when creating a class like Foo. If you were to follow the pattern above, you’d again define a custom method and assign it as the __new__() method for the class of which Foo is an instance. Foo is an instance of the type metaclass, so the code looks something like this:

现在,正如已经重申的,类也是对象。 假设您要在创建类似Foo的类时类似地自定义实例化行为。 如果要遵循上述模式,则将再次定义一个自定义方法,并将其分配为Foo是其实例的类的__new__()方法。 Footype元类的实例,因此代码如下所示:

Except, as you can see, you can’t reassign the __new__() method of the type metaclass. Python doesn’t allow it.

如您所见,除了不能重新分配type元类的__new__()方法。 Python不允许这样做。

This is probably just as well. type is the metaclass from which all new-style classes are derived. You really shouldn’t be mucking around with it anyway. But then what recourse is there, if you want to customize instantiation of a class?

这可能也是一样。 type是派生所有新样式类的元类。 无论如何,您真的不应该对此乱搞。 但是,如果要自定义类的实例化,那又有什么办法?

One possible solution is a custom metaclass. Essentially, instead of mucking around with the type metaclass, you can define your own metaclass, which derives from type, and then you can muck around with that instead.

一种可能的解决方案是自定义元类。 本质上,不必定义type元类,而可以定义自己的元类,该元类派生自type ,然后可以对其进行分类。

The first step is to define a metaclass that derives from type, as follows:

第一步是定义一个从type派生的元类,如下所示:

 >>> >>>  class class MetaMeta (( typetype ):
):
...     ...     def def __new____new__ (( clscls , , namename , , basesbases , , dctdct ):
):
...         ...         x x = = supersuper ()() .. __new____new__ (( clscls , , namename , , basesbases , , dctdct )
)
...         ...         xx .. attr attr = = 100
100
...         ...         return return x
x
...
...

The definition header class Meta(type): specifies that Meta derives from type. Since type is a metaclass, that makes Meta a metaclass as well.

定义标头class Meta(type):指定Meta源自type 。 由于type是元类,因此也使Meta成为元类。

Note that a custom __new__() method has been defined for Meta. It wasn’t possible to do that to the type metaclass directly. The __new__() method does the following:

请注意,已为Meta定义了自定义__new__()方法。 直接对type元类执行此操作是不可能的。 __new__()方法执行以下操作:

  • Delegates via super() to the __new__() method of the parent metaclass (type) to actually create a new class
  • Assigns the custom attribute attr to the class, with a value of 100
  • Returns the newly created class
  • 通过super()委托给父元类( type )的__new__()方法,以实际创建一个新类
  • 将自定义属性attr分配给类,值为100
  • 返回新创建的类

Now the other half of the voodoo: Define a new class Foo and specify that its metaclass is the custom metaclass Meta, rather than the standard metaclass type. This is done using the metaclass keyword in the class definition as follows:

现在,伏都教的另一半:定义一个新的类Foo并指定其元类是自定义元类Meta ,而不是标准元类type 。 通过在类定义中使用metaclass关键字来完成此操作,如下所示:

Voila! Foo has picked up the attr attribute automatically from the Meta metaclass. Of course, any other classes you define similarly will do likewise:

瞧! FooMeta元类自动获取了attr属性。 当然,类似地定义的任何其他类也将这样做:

 >>> >>>  class class BarBar (( metaclassmetaclass == MetaMeta ):
):
...     ...     pass
pass
...
...
>>> >>>  class class QuxQux (( metaclassmetaclass == MetaMeta ):
):
...     ...     pass
pass
...
...
>>> >>>  BarBar .. attrattr , , QuxQux .. attr
attr
(100, 100)
(100, 100)

In the same way that a class functions as a template for the creation of objects, a metaclass functions as a template for the creation of classes. Metaclasses are sometimes referred to as class factories.

与类充当创建对象的模板的方式相同,元类充当创建类的模板的功能。 元类有时称为类工厂

Compare the following two examples:

比较以下两个示例:

Object Factory:

对象工厂:

Class Factory:

类工厂:

 >>> >>>  class class MetaMeta (( typetype ):
):
...     ...     def def __init____init__ (
(
...         ...         clscls , , namename , , basesbases , , dct
dct
...     ...     ):
):
...         ...         clscls .. attr attr = = 100
100
...
...
>>> >>>  class class XX (( metaclassmetaclass == MetaMeta ):
):
...     ...     pass
pass
...
...
>>> >>>  XX .. attr
attr
100

100

>>> >>>  class class YY (( metaclassmetaclass == MetaMeta ):
):
...     ...     pass
pass
...
...
>>> >>>  YY .. attr
attr
100

100

>>> >>>  class class ZZ (( metaclassmetaclass == MetaMeta ):
):
...     ...     pass
pass
...
...
>>> >>>  ZZ .. attr
attr
100
100

这真的有必要吗? (Is This Really Necessary?)

As simple as the above class factory example is, it is the essence of how metaclasses work. They allow customization of class instantiation.

就像上面的类工厂示例一样简单,这是元类如何工作的本质。 它们允许自定义类实例化。

Still, this is a lot of fuss just to bestow the custom attribute attr on each newly created class. Do you really need a metaclass just for that?

尽管如此,在每个新创建的类上赋予自定义属性attr还是一件大事。 您真的需要一个元类吗?

In Python, there are at least a couple other ways in which effectively the same thing can be accomplished:

在Python中,至少有几种其他方法可以有效地完成同一件事:

Simple Inheritance:

简单继承:

Class Decorator:

类装饰器:

 >>> >>>  def def decoratordecorator (( clscls ):
):
...     ...     class class NewClassNewClass (( clscls ):
):
...         ...         attr attr = = 100
100
...     ...     return return NewClass
NewClass
...
...
>>> >>>  @decorator
@decorator
... ...  class class XX :
:
...     ...     pass
pass
...
...
>>> >>>  @decorator
@decorator
... ...  class class YY :
:
...     ...     pass
pass
...
...
>>> >>>  @decorator
@decorator
... ...  class class ZZ :
:
...     ...     pass
pass
...

...

>>> >>>  XX .. attr
attr
100
100
>>> >>>  YY .. attr
attr
100
100
>>> >>>  ZZ .. attr
attr
100
100

结论 (Conclusion)

As Tim Peters suggests, metaclasses can easily veer into the realm of being a “solution in search of a problem.” It isn’t typically necessary to create custom metaclasses. If the problem at hand can be solved in a simpler way, it probably should be. Still, it is beneficial to understand metaclasses so that you understand Python classes in general and can recognize when a metaclass really is the appropriate tool to use.

正如蒂姆·彼得斯(Tim Peters)所建议的那样, 元类很容易进入“寻找问题的解决方案”的境界。 通常不需要创建自定义元类。 如果眼前的问题可以用更简单的方法解决,那应该是可以的。 尽管如此,理解元类还是有好处的,这样您就可以大致理解Python类 ,并可以识别何时才真正适合使用元类。

翻译自: https://www.pybloggers.com/2018/05/python-metaclasses/

python元类

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值