什么是metaClasses Python?

在 Python, 什么是metaClasses和我们使用的东西?
已邀请:

裸奔

赞同来自:

像对象这样的课程

在处理MetaClasses之前,您需要通过主课程进行 Python. 和 Python 对从语言借用的课程有一个非常奇特的想法 Smalltalk.

在大多数语言中,类只是描述如何创建对象的代码的片段。 这也是一种真理 Python :


>>> class ObjectCreator/object/:
... pass
...

>>> my_object = ObjectCreator//
>>> print/my_object/
<__main__.ObjectCreator object at 0x8974f2c>


但课程不仅仅是 Python. 类也是对象。

是的,对象。

使用关键字后
class

, Python 执行它并创建
OBJECT. 操作说明


>>> class ObjectCreator/object/:
... pass
...


创建一个名称的对象 "ObjectCreator".

这个对象 /班级/ 它能够创建对象 /套/,
这就是为什么他是一堂课

.

但这仍然是一个对象,因此:

您可以将其分配给变量

你可以复制它

您可以为其添加属性。

您可以将其作为函数参数传递。

例如:


>>> print/ObjectCreator/ # you can print a class because it's an object
<class '__main__.objectcreator'="">
&gt;&gt;&gt; def echo/o/:
... print/o/
...
&gt;&gt;&gt; echo/ObjectCreator/ # you can pass a class as a parameter
<class '__main__.objectcreator'="">
&gt;&gt;&gt; print/hasattr/ObjectCreator, 'new_attribute'//
False
&gt;&gt;&gt; ObjectCreator.new_attribute = 'foo' # you can add attributes to a class
&gt;&gt;&gt; print/hasattr/ObjectCreator, 'new_attribute'//
True
&gt;&gt;&gt; print/ObjectCreator.new_attribute/
foo
&gt;&gt;&gt; ObjectCreatorMirror = ObjectCreator # you can assign a class to a variable
&gt;&gt;&gt; print/ObjectCreatorMirror.new_attribute/
foo
&gt;&gt;&gt; print/ObjectCreatorMirror///
&lt;__main__.ObjectCreator object at 0x8997b4c&gt;


动态创造课程

由于类是对象,您可以像任何其他对象一样创建它们。

首先,您可以使用功能创建一个类
class

:


&gt;&gt;&gt; def choose_class/name/:
... if name == 'foo':
... class Foo/object/:
... pass
... return Foo # return the class, not an instance
... else:
... class Bar/object/:
... pass
... return Bar
...
&gt;&gt;&gt; MyClass = choose_class/'foo'/
&gt;&gt;&gt; print/MyClass/ # the function returns a class, not an instance
<class '__main__.foo'="">
&gt;&gt;&gt; print/MyClass/// # you can create an object from this class
&lt;__main__.Foo object at 0x89c6d4c&gt;


但这不是那么动态,因为你仍然必须自己写整个班级。

由于类是对象,因此必须由某些东西生成。

使用关键字时
class

, Python 自动创建此对象。 但怎么样?
大多数事情都在 Python, 它让您有机会手动进行。

记住这个功能
type

? 旧的好功能让您了解什么
类型对象:


&gt;&gt;&gt; print/type/1//
<type 'int'="">
&gt;&gt;&gt; print/type/"1"//
<type 'str'="">
&gt;&gt;&gt; print/type/ObjectCreator//
<type 'type'="">
&gt;&gt;&gt; print/type/ObjectCreator////
<class '__main__.objectcreator'="">


出色地,
http://docs.python.org/2/libra ... 3type
type

有一个完全不同的能力,它也可以在飞行中创造课程。
type

可以接受类描述作为参数
和返回课程。

/我知道这是愚蠢的,相同的功能可以有两个完全不同的用途,具体取决于您传递给它的参数。 这是由于反向的问题
兼容B. Python/


type

以这种方式工作:


type/name, bases, attrs/


在哪里:


name


: 班级名称


bases


: 父级成熟 /继承可以是空的/


attrs


: 字典包含属性名称和值

, 例如:


&gt;&gt;&gt; class MyShinyClass/object/:
... pass


因此,它可以手动创建:


&gt;&gt;&gt; MyShinyClass = type/'MyShinyClass', //, {}/ # returns a class object
&gt;&gt;&gt; print/MyShinyClass/
<class '__main__.myshinyclass'="">
&gt;&gt;&gt; print/MyShinyClass/// # create an instance with the class
&lt;__main__.MyShinyClass object at 0x8997cec&gt;


您会注意到我们使用 "MyShinyClass" 作为班级名称
作为用于存储对类的引用的变量。 它们可以不同
但没有理由使一切复杂化。


type

采用字典来确定类属性。 所以:


&gt;&gt;&gt; class Foo/object/:
... bar = True


可以翻译:


&gt;&gt;&gt; Foo = type/'Foo', //, {'bar':True}/


并用作常规课程:


&gt;&gt;&gt; print/Foo/
<class '__main__.foo'="">
&gt;&gt;&gt; print/Foo.bar/
True
&gt;&gt;&gt; f = Foo//
&gt;&gt;&gt; print/f/
&lt;__main__.Foo object at 0x8a9b84c&gt;
&gt;&gt;&gt; print/f.bar/
True


当然,你可以继承他,所以:


&gt;&gt;&gt; class FooChild/Foo/:
... pass


将:


&gt;&gt;&gt; FooChild = type/'FooChild', /Foo,/, {}/
&gt;&gt;&gt; print/FooChild/
<class '__main__.foochild'="">
&gt;&gt;&gt; print/FooChild.bar/ # bar is inherited from Foo
True


最终,您将想向您的课程添加方法。 刚确定功能
使用相应的签名并将其分配为属性。


&gt;&gt;&gt; def echo_bar/self/:
... print/self.bar/
...
&gt;&gt;&gt; FooChild = type/'FooChild', /Foo,/, {'echo_bar': echo_bar}/
&gt;&gt;&gt; hasattr/Foo, 'echo_bar'/
False
&gt;&gt;&gt; hasattr/FooChild, 'echo_bar'/
True
&gt;&gt;&gt; my_foo = FooChild//
&gt;&gt;&gt; my_foo.echo_bar//
True


您可以在动态类创建后添加更多方法,就像将方法添加到通常创建的类对象一样。


&gt;&gt;&gt; def echo_bar_more/self/:
... print/'yet another method'/
...
&gt;&gt;&gt; FooChild.echo_bar_more = echo_bar_more
&gt;&gt;&gt; hasattr/FooChild, 'echo_bar_more'/
True


你看看我们去哪里:在 Python 类是对象,您可以动态地创建一个类。

这是 , 他在做什么 Python, 使用关键字时
class

, 他用一个metaclass做了它。

什么是metaClasses. /最后/

metaClasses是 'stuff', 它创造了课程。

您定义类以创建对象,对吗?

但我们了解到课程 Python 是对象。

嗯,MetaClasses是创造这些物体的原因。 他们是课程课程
你可以以这种方式展示它们:


MyClass = MetaClass//
my_object = MyClass//


你见过这个
type

允许您做那样的事情:


MyClass = type/'MyClass', //, {}/


这是因为功能
type

事实上,这是一个metaclass。
type

-这是
metaclass,哪个 Python 用于在幕后创建所有类。

现在你很惊讶为什么,该死的,它是用小写的,而不是
Type

?

嗯,我想 , 这是一个一致性的问题
str

, 创造的课程
字符串对象
int

一个创建整数对象的类。
type

-这是
只需创建类对象的类。

您可以通过检查该属性来验证这一点
__class__

.

一切,我的意思是一切都是对象 Python. 这包括 ints,
行,函数和课程。 所有这些都是物体。 和所有人
是从课堂上创建的:


&gt;&gt;&gt; age = 35
&gt;&gt;&gt; age.__class__
<type 'int'="">
&gt;&gt;&gt; name = 'bob'
&gt;&gt;&gt; name.__class__
<type 'str'="">
&gt;&gt;&gt; def foo//: pass
&gt;&gt;&gt; foo.__class__
<type 'function'="">
&gt;&gt;&gt; class Bar/object/: pass
&gt;&gt;&gt; b = Bar//
&gt;&gt;&gt; b.__class__
<class '__main__.bar'="">


那么是什么
__class__

任何人
__class__

?


&gt;&gt;&gt; age.__class__.__class__
<type 'type'="">
&gt;&gt;&gt; name.__class__.__class__
<type 'type'="">
&gt;&gt;&gt; foo.__class__.__class__
<type 'type'="">
&gt;&gt;&gt; b.__class__.__class__
<type 'type'="">


因此,Metaclass只是一种创建类对象的材料。

你可以称之为 'class factory', 如果你想。


type

- 这是使用的内置Metaclass Python, 但是,当然,您可以创建自己的。
自己的metaclass。

属性
http://docs.python.org/2/refer ... ass__
在 Python 2 您可以添加属性
__metaclass__

写一堂课时 /有关语法,请参阅以下部分 Python 3/:


class Foo/object/:
__metaclass__ = something...
[...]


如果你这样做,那么 Python 将使用metaclass创建一个类
Foo

.

仔细,很难。

首先你写道
class Foo/object/

, 但是类对象
Foo

尚未创建
心里。

Python 会发现
__metaclass__

在课堂定义中。 如果他找到他
它将使用它来创建一类对象。
Foo

. 如果不是,它将使用
type

创建一个类。

几次阅读它。

当你这样做时:


class Foo/Bar/:
pass


Python 执行以下操作:

有一个属性
__metaclass__


Foo

?

如果是,则在内存中创建类对象 /我说课堂对象,留在这里/ 名称
Foo

, 使用什么
__metaclass__

.

如果一个 Python 找不到
__metaclass__

, 他会发现
__metaclass__

在水平 MODULE 并试图做同样的事情 /但仅适用于不继承任何东西的课程,大多是旧风格的阶级/.

然后,如果他找不到任何东西
__metaclass__

, 它将使用自己的metaclass
Bar

/第一个父母/ /默认情况下可以
type

/ 创建类对象。

在这里谨慎归功
__metaclass__

不是继承,父母元 /
Bar.__class__

/ 将。 如果一个
Bar

二手归因
__metaclass__

, 谁创造了
Bar


type//

/但不是
type.__new__//

/, 子类不会继承此行为。

现在主要问题是你可以投入
__metaclass__

?

答案是:可以创建一个类的东西。

什么可以创造一个课程?
type

, 或所有的子类或使用它。

Metachellable B. Python 3

MetaClass安装语法已更改 Python 3:


class Foo/object, metaclass=something/:
...


, 这是属性
__metaclass__

不再用于基本类列表中的一个关键参数。

然而,MetaClasses的行为仍然存在
https://www.python.org/dev/peps/pep-3115/
最多。 .

有一件事添加到metablasses中 python 3, 正是您还可以将属性传输为Metaclass中的关键字参数,例如:


class Foo/object, metaclass=something, kwarg1=value1, kwarg2=value2/:
...


阅读下面的部分 python 他和它一起调查。

自定义元壳

MetaClass自动课程变更的主要目标
创建它时。

通常你这样做 APIs, 您想要创建对应的类的位置
当前的上下文。

想象一个愚蠢的例子,当你决定模块中的所有类时
必须在大写中写入自己的属性。 有几种方式
做到这一点,但其中一个是安装
__metaclass__

在模块级别。

因此,将使用此MetAclarse创建此模块的所有类,
我们只需要说一个元队将所有属性转换为大写。

幸运的是,
__metaclass__

事实上,它可以是任何造成的,它不必是 a
正式的课堂 /我知道了 'class' 他的名字不应该是
班级,让我们说......但它很有用/.

因此,我们将从使用该函数的简单示例开始。


# the metaclass will automatically get passed the same argument
# that you usually pass to `type`
def upper_attr/future_class_name, future_class_parents, future_class_attrs/:
"""
Return a class object, with the list of its attribute turned
into uppercase.
"""
# pick up any attribute that doesn't start with '__' and uppercase it
uppercase_attrs = {
attr if attr.startswith/"__"/ else attr.upper//: v
for attr, v in future_class_attrs.items//
}

# let `type` do the class creation
return type/future_class_name, future_class_parents, uppercase_attrs/

__metaclass__ = upper_attr # this will affect all classes in the module

class Foo//: # global __metaclass__ won't work with "object" though
# but we can define __metaclass__ here instead to affect only this class
# and this will work with "object" children
bar = 'bip'


让我们检查:


&gt;&gt;&gt; hasattr/Foo, 'bar'/
False
&gt;&gt;&gt; hasattr/Foo, 'BAR'/
True
&gt;&gt;&gt; Foo.BAR
'bip'


现在让我们这样做,但是使用一个真正的metaclasses:


# remember that `type` is actually a class like `str` and `int`
# so you can inherit from it
class UpperAttrMetaclass/type/:
# __new__ is the method called before __init__
# it's the method that creates the object and returns it
# while __init__ just initializes the object passed as parameter
# you rarely use __new__, except when you want to control how the object
# is created.
# here the created object is the class, and we want to customize it
# so we override __new__
# you can do some stuff in __init__ too if you wish
# some advanced use involves overriding __call__ as well, but we won't
# see this
def __new__/upperattr_metaclass, future_class_name,
future_class_parents, future_class_attrs/:
uppercase_attrs = {
attr if attr.startswith/"__"/ else attr.upper//: v
for attr, v in future_class_attrs.items//
}
return type/future_class_name, future_class_parents, uppercase_attrs/


让我们重写前述,但现在有更短的变化的变量名,当我们知道他们的意思时:


class UpperAttrMetaclass/type/:
def __new__/cls, clsname, bases, attrs/:
uppercase_attrs = {
attr if attr.startswith/"__"/ else attr.upper//: v
for attr, v in attrs.items//
}
return type/clsname, bases, uppercase_attrs/


您可能会注意到额外的论点
cls

. 有
它没有什么特别的:
__new__

始终获得一个类,其中它被定义为第一个参数。 就像你一样
self

对于接收实例作为第一个参数的传统方法,或类方法的定义类。

但这并不是正确的 OOP. 我们称之为
type

直接,而不是覆盖或呼叫父母
__new__

. :


class UpperAttrMetaclass/type/:
def __new__/cls, clsname, bases, attrs/:
uppercase_attrs = {
attr if attr.startswith/"__"/ else attr.upper//: v
for attr, v in attrs.items//
}
return type.__new__/cls, clsname, bases, uppercase_attrs/


我们可以让它仍然清洁 , 使用
super

, 什么促进遗产 /因为是的,您可能拥有从类型继承的MetaClass内继承的甲烷类/:


class UpperAttrMetaclass/type/:
def __new__/cls, clsname, bases, attrs/:
uppercase_attrs = {
attr if attr.startswith/"__"/ else attr.upper//: v
for attr, v in attrs.items//
}
return super/UpperAttrMetaclass, cls/.__new__/
cls, clsname, bases, uppercase_attrs/


哦,在 python 3, 例如,如果使用关键字参数进行此调用,例如:


class Foo/object, metaclass=MyMetaclass, kwarg1=value1/:
...


它在Metaclass中翻译成用于使用它:


class MyMetaclass/type/:
def __new__/cls, clsname, bases, dct, kwargs1=default/:
...


就这样。 事实上,Getablasses没有任何关于。

使用甲烷的代码复杂性的原因不是那样
至于MetaLlates,它是因为您通常使用MetaClasses来执行erversions
, 依靠内省 , 操纵遗传 vars, 如
__dict__

等等。

实际上,MetaClasses对黑魔法特别有用,这意味着
, 以及复杂的东西。 但是自己,他们很简单:

拦截创建一个类

改变类

返回更改的类

为什么你使用元舱的类而不是函数?

只要
__metaclass__

可以采取任何叫做的对象,为什么要使用该类
由于这显然更困难了?

为此有几个原因:

意图是明确的。 当你读书的时候
UpperAttrMetaclass/type/

, 你懂
, 这是如此

您可以使用 OOP. Metaclass可以从甲烷来源,重新定义父母方法。 MetaClasses甚至可以使用MetaClasses。

如果您指定了MetaClass类,则将类子类将是其MetAclarse的副本,但不使用MetaClass函数。

你可以更好地训练你的代码。 你永远不会使用metaclasses
琐碎的,如上面的例子。 这通常是为了复杂的东西。 可用性
在一个班级中创建多种方法和组的能力非常有用
促进读取代码。

你可以坚持
__new__

,
__init__


__call__

. 这将允许
你做不同的事情。 即使你通常可以全部做到这一切
__new__

,
有些人只是使用更舒服
__init__

.

他们被称为Methaclasses,该死的! 它应该意味着什么!

你为什么需要MetaClasses?

现在是主要问题。 为什么你需要使用一些不可征收的函数受到错误?

好吧,通常你不是:

metaClasses是深度魔法
99% 用户永远不应该担心它。
如果你想知道他们是否需要你,
你不这样做 /真正的人
需要他们,充满信心地知道这一点
他们需要它们,不需要
解释为什么/.

Python 格鲁鲁·蒂姆彼得斯

metaclarse的主要使用是创作 API. 这个典型的例子是 Django ORM. 这允许您确定这样的内容:


class Person/models.Model/:
name = models.CharField/max_length=30/
age = models.IntegerField//


但如果你这样做:


person = Person/name='bob', age='35'/
print/person.age/


他不会回归物体
IntegerField

. 他会回来
int

甚至可以直接从数据库中取出它。

这是可能的,因为
models.Model

确定
__metaclass__


使用一些将转向的魔法
Person

, 您刚用简单的运营商定义
, 在数据库字段的复杂钩子中。

Django 让一些复杂的简单,曝光简单 API
并使用MetaClasses,来自此的娱乐代码 API, 做实际的工作
对于鳞片。

最后一个字

首先,您知道类是可以创建实例的对象。

好吧,事实上,课程本身是副本。 关于metaclasses。


&gt;&gt;&gt; class Foo/object/: pass
&gt;&gt;&gt; id/Foo/
142630324


一切都是对象 Python, 所有这些都是课程的实例
, 一份副本的元峰。

除了
type

.


type

- 它实际上是它自己的metaclass。 这不是你能做的
会在纯净中繁殖 Python, 并通过实施级别的欺骗性完成
.

其次,元壳是复杂的。 你可能不想用它们
非常简单的班级变化。 您可以使用两种不同的方法更改类:

http://en.wikipedia.org/wiki/Monkey_patch
装饰课程

99% 从那些情况下,当您需要更改类时,最好更好地使用它们。

但 98% 您无需更改类。
</type></type></type></type></class></type></type></type></class></class></class></class></type></type></type></class></class></class>

喜特乐

赞同来自:

metache类是类类。 该类确定类实例的行为方式 /即。融合/, 虽然MetaClass确定了类的行为方式。 班级 - 这是一个MetaClass副本。

而在 Python 您可以使用任意尝试对象进行MetaClasses。 /如图所示 Jerub/, 最好的方法是使它成为实际的课程。
type

- 这是一个普通的metaclass Python.
type

本身,它是类,这是他自己的类型。 你将无法重新创建类似的东西
type

纯V. Python, 但 Python 有点欺骗。 创建自己的metaclass Python, 你真的只想要一个子类
type

.

Metaclass最常被用作班级工厂。 创建一个调用类的对象时, Python 创造一个新的课程 /执行操作员时 'class'/, 由metaclass引起的。 因此,与常规方法组合
__init__


__new__

metaClasses允许您执行 'extra things' 例如,在创建类时,在任何注册表中注册一个新类或替换完全不同的类。

当运营商时
class

表演, Python 首先执行操作员的主体
class

作为常规代码块。 结果名称空间 /dict/ 包含属性 class-to-be. 通过查看基本类来确定metaclass class-to-be /遗传是元壳/, attributa.
__metaclass__

class-to-be /如果是的话/ 或全局变量
__metaclass__

. 然后使用名称,数据库和类属性调用metaclass以创建其实例。

但是,MetaClasses实际确定

一种

班级,不只是为他的工厂,所以你可以和他们做得更多。 例如,您可以确定Metaclass中的常用方法。 这些元方法喜欢 classmethods 在没有实例的情况下可以在课堂上调用它们,但它们也不喜欢 classmethods 他们不能由班级实例引起的事实。
type.__subclasses__//

- 这是Metaclass中的方法的示例
type

. 您还可以确定通常的方法。 'magic', 如那个
__add__

,
__iter__


__getattr__

, 实现或更改类行为。

以下是位和块的聚合示例:


def make_hook/f/:
"""Decorator to turn 'foo' method into '__foo__'"""
f.is_hook = 1
return f

class MyType/type/:
def __new__/mcls, name, bases, attrs/:

if name.startswith/'None'/:
return None

# Go over attributes and see if they should be renamed.
newattrs = {}
for attrname, attrvalue in attrs.iteritems//:
if getattr/attrvalue, 'is_hook', 0/:
newattrs['__%s__' % attrname] = attrvalue
else:
newattrs[attrname] = attrvalue

return super/MyType, mcls/.__new__/mcls, name, bases, newattrs/

def __init__/self, name, bases, attrs/:
super/MyType, self/.__init__/name, bases, attrs/

# classregistry.register/self, self.interfaces/
print "Would register class %s now." % self

def __add__/self, other/:
class AutoClass/self, other/:
pass
return AutoClass
# Alternatively, to autogenerate the classname as well as the class:
# return type/self.__name__ + other.__name__, /self, other/, {}/

def unregister/self/:
# classregistry.unregister/self/
print "Would unregister class %s now." % self

class MyObject:
__metaclass__ = MyType


class NoneSample/MyObject/:
pass

# Will print "NoneType None"
print type/NoneSample/, repr/NoneSample/

class Example/MyObject/:
def __init__/self, value/:
self.value = value
@make_hook
def add/self, other/:
return self.__class__/self.value + other.value/

# Will unregister the class
Example.unregister//

inst = Example/10/
# Will fail with an AttributeError
#inst.unregister//

print inst + inst
class Sibling/MyObject/:
pass

ExampleSibling = Example + Sibling
# ExampleSibling is now a subclass of both Example and Sibling /with no
# content of its own/ although it will believe it's called 'AutoClass'
print ExampleSibling
print ExampleSibling.__mro__

喜特乐

赞同来自:

请注意,此答案是指的 Python 2.x, 因为他写的 2008 一年,MetaClasses略有不同 3.x.

MetaClasses是一种秘密酱 'class' 工作。 调用新样式对象的默认元类。 'type'.


class type/object/
| type/object/ -> the object's type
| type/name, bases, dict/ -> a new type


接受的金属蹄类 3 争论。 "

姓名

", "

基础

" 和 "

迪克

"

这是神秘开始的地方。 请参阅从此示例的类定义中获取的名称,foundation和dict。


class ThisIsTheName/Bases, Are, Here/:
All_the_code_here
def doesIs/create, a/:
dict


让我们定义一个将展示如何的metaclass '

class:

' 导致它。


def test_metaclass/name, bases, dict/:
print 'The Class Name is', name
print 'The Class Bases are', bases
print 'The dict has', len/dict/, 'elems, the keys are', dict.keys//

return "yellow"

class TestName/object, None, int, 1/:
__metaclass__ = test_metaclass
foo = 1
def baz/self, arr/:
pass

print 'TestName = ', repr/TestName/

# output =>
The Class Name is TestName
The Class Bases are /<type 'object'="">, None, <type 'int'="">, 1/
The dict has 4 elems, the keys are ['baz', '__module__', 'foo', '__metaclass__']
TestName = 'yellow'


而现在是一个真正意味着什么的例子,将自动在列表中制作变量 "attributes" 在课堂上建立等 None.


def init_attributes/name, bases, dict/:
if 'attributes' in dict:
for attr in dict['attributes']:
dict[attr] = None

return type/name, bases, dict/

class Initialised/object/:
__metaclass__ = init_attributes
attributes = ['foo', 'bar', 'baz']

print 'foo =&gt;', Initialised.foo
# output=&gt;
foo =&gt; None


请注意,这个神奇的行为
Initialised

得到一个metaclass
init_attributes

, 不传输给子类
Initialised

.

以下是一个更具体的示例,展示了如何子类 'type' 创建MetaClass,在创建类时执行操作。 这很困难:


class MetaSingleton/type/:
instance = None
def __call__/cls, *args, **kw/:
if cls.instance is None:
cls.instance = super/MetaSingleton, cls/.__call__/*args, **kw/
return cls.instance

class Foo/object/:
__metaclass__ = MetaSingleton

a = Foo//
b = Foo//
assert a is b


</type></type>

石油百科

赞同来自:

其他人解释了MetaClasses如何工作以及它们如何适应类型系统 Python. 这是他们可以使用的例子。 作为我写道的测试的一部分,我想跟踪识别课程以稍后创建其副本的顺序。 在我看来,它最容易用MetaClass做到这一点。


class MyMeta/type/:

counter = 0

def __init__/cls, name, bases, dic/:
type.__init__/cls, name, bases, dic/
cls._order = MyMeta.counter
MyMeta.counter += 1

class MyType/object/: # Python 2
__metaclass__ = MyMeta

class MyType/metaclass=MyMeta/: # Python 3
pass


所有这些是子类
MyType

, 然后获取类属性
_order

, 这是写入课程的命令。

莫问

赞同来自:

使用Methaclasses的一种方法是自动添加每个实例的新属性和方法。

例如,如果你看看
http://docs.djangoproject.com/ ... dels/
, 他们的定义看起来有点令人困惑。 它看起来好像只定义类的属性:


class Person/models.Model/:
first_name = models.CharField/max_length=30/
last_name = models.CharField/max_length=30/


但是,在执行对象期间 Person 充满了各种有用的方法。 看
http://code.djangoproject.com/ ... se.py
对于一些惊人的甲烷。

小姐请别说爱

赞同来自:

我想介绍 ONLamp MetaClasses的编程是很好的,尽管他已经过了几年了,但仍然非常好地介绍了这一话题。

http://www.onlamp.com/pub/a/py ... .html
/存档
https://web.archive.org/web/20 ... .html
/

简而言之:一个类是一个用于创建实例的方案,Metaclass是创建类的方案。 很容易看到 Python 类也应该是一流的对象,以确保这种行为。

我从来没有自己写过他,但我认为可以看到最令人愉快的代码
http://www.djangoproject.com/
Django . 模型类使用MetaClass方法来确保编写新模型或类别的声明方式。 虽然Metaclass创建了一个类,但所有成员都能获得配置类本身的能力。

http://docs.djangoproject.com/ ... 23id3
http://code.djangoproject.com/ ... 23L25
去做

它仍然可以说:如果你不知道什么是甲基猿是什么,他们所处的可能性

不需要

平等的 99%.

裸奔

赞同来自:

什么是metaClasses? 你为什么用它们?

TLDR: MetaClass以与类创建的相同方式创建并确定类的行为,并确定实例的行为。

伪码:


>>> Class/.../
instance


以上所有人都应该看起来很熟悉。 好吧,它来自哪里
Class

? 这是一个metaclass副本 /也是伪代码/:


>>> Metaclass/.../
Class


在实际代码中,我们可以传输默认的元类,
type

, 全部 , 我们需要创建一个类实例,我们将获得一个课程:


>>> type/'Foo', /object,/, {}/ # requires a name, bases, and a namespace
<class '__main__.foo'="">


说话不同

该类指的是实例以与类的Metaclass相同的方式。

当我们创建对象的实例时,我们得到一个实例:


&gt;&gt;&gt; object// # instantiation of class
<object 0x7f9069b4e0b0="" at="" object=""> # instance


同样,当我们用默认的元类明确定义类时,
type

, 我们创建了它的实例:


&gt;&gt;&gt; type/'Object', /object,/, {}/ # instantiation of metaclass
<class '__main__.object'=""> # instance


换句话说,一个类是MetaClassa的实例:


&gt;&gt;&gt; isinstance/object, type/
True


第三,metaclass是类类。


&gt;&gt;&gt; type/object/ == type
True
&gt;&gt;&gt; object.__class__
<class 'type'="">


写入类定义时和 Python 执行它,它使用Metaclass来创建类对象的实例 /反过来,这将用于创建此类的实例/.

正如我们可以使用类定义要更改对象的用户实例的行为,我们可以使用Metaclasses类定义来更改类对象的行为。

为什么可以使用? 的
https://docs.python.org/3/refe ... ample
:

使用MetaClasses的可能性是无穷无尽的。 调查的一些想法包括日志记录,检查界面,自动委派,自动属性,代理服务器,框架和自动资源 locking/synchronization.

但是,通常建议使用用户,以避免使用MetaClasses而无需很多需求。

每次创建类时都使用Metaclass:

例如,当您编写类定义时,如此


class Foo/object/: 
'demo'


您创建了类对象的实例。


&gt;&gt;&gt; Foo
<class '__main__.foo'="">
&gt;&gt;&gt; isinstance/Foo, type/, isinstance/Foo, object/
/True, True/


这是在功能上造成的相同的事情
type

具有适当的参数并分配具有相同名称的变量的结果:


name = 'Foo'
bases = /object,/
namespace = {'__doc__': 'demo'}
Foo = type/name, bases, namespace/


请注意,有些东西会自动添加到
__dict__

, 也就是说,命名空间:


&gt;&gt;&gt; Foo.__dict__
dict_proxy/{'__dict__': <attribute '__dict__'="" 'foo'="" objects="" of="">,
'__module__': '__main__', '__weakref__': <attribute '__weakref__'="" 'foo'="" objects="" of="">, '__doc__': 'demo'}/


metaclass.

我们在这两种情况下创建的对象是相等的
type

.

/课程内容的注意事项
__dict__

:
__module__

存在,因为课程应该知道它们定义的位置,以及
__dict__


__weakref__

存在,因为我们没有定义
__slots__

- 要是我们
https://coderoad.ru/472000/
我们将在副本中保存一点空间,我们可以禁止
__dict__


__weakref__

, 通过排除它们。 例如:


&gt;&gt;&gt; Baz = type/'Bar', /object,/, {'__doc__': 'demo', '__slots__': //}/
&gt;&gt;&gt; Baz.__dict__
mappingproxy/{'__doc__': 'demo', '__slots__': //, '__module__': '__main__'}/


80 但我分心了。/

我们可以扩展
type

就像类的任何其他定义一样:

这是默认值
__repr__

课程:


&gt;&gt;&gt; Foo
<class '__main__.foo'="">


在编写对象时,我们可以默认做出最有价值的事情之一 Python, - 它给了他一个好的
__repr__

. 当我们打电话的时候
help/repr/

, 我们了解到有一个很好的考验
__repr__

, 这也需要平等面团 -
obj == eval/repr/obj//

. 下一个简单的实现
__repr__


__eq__

对于我们类型类型的类的实例,它为我们提供了一个可以改善默认类工作的演示
__repr__

:


class Type/type/:
def __repr__/cls/:
"""
&gt;&gt;&gt; Baz
Type/'Baz', /Foo, Bar,/, {'__module__': '__main__', '__doc__': None}/
&gt;&gt;&gt; eval/repr/Baz//
Type/'Baz', /Foo, Bar,/, {'__module__': '__main__', '__doc__': None}/
"""
metaname = type/cls/.__name__
name = cls.__name__
parents = ', '.join/b.__name__ for b in cls.__bases__/
if parents:
parents += ','
namespace = ', '.join/': '.join/
/repr/k/, repr/v/ if not isinstance/v, type/ else v.__name__//
for k, v in cls.__dict__.items///
return '{0}/\'{1}\', /{2}/, {{{3}}}/'.format/metaname, name, parents, namespace/
def __eq__/cls, other/:
"""
&gt;&gt;&gt; Baz == eval/repr/Baz//
True
"""
return /cls.__name__, cls.__bases__, cls.__dict__/ == /
other.__name__, other.__bases__, other.__dict__/


所以现在,当我们使用此元册创建一个对象时,
__repr__

, 反映在命令提示符上,提供比默认值更少的丑陋视图:


&gt;&gt;&gt; class Bar/object/: pass
&gt;&gt;&gt; Baz = Type/'Baz', /Foo, Bar,/, {'__module__': '__main__', '__doc__': None}/
&gt;&gt;&gt; Baz
Type/'Baz', /Foo, Bar,/, {'__module__': '__main__', '__doc__': None}/


有良好的
__repr__

, 为类实例定义,我们有更强大的调试代码的能力。 但是,进一步验证
eval/repr/Class//

不太可能 /由于函数从默认值计算
__repr__

/.

预期用途:
__prepare__

空间名称

例如,如果我们想知道类方法创建了哪些顺序,我们可以提供有序 dict 作为类命名空间。 我们会做到
__prepare__

, 哪一个
https://docs.python.org/3/refe ... space
:


from collections import OrderedDict

class OrderedType/Type/:
@classmethod
def __prepare__/metacls, name, bases, **kwargs/:
return OrderedDict//
def __new__/cls, name, bases, namespace, **kwargs/:
result = Type.__new__/cls, name, bases, dict/namespace//
result.members = tuple/namespace/
return result


并使用:


class OrderedMethodsObject/object, metaclass=OrderedType/:
def method1/self/: pass
def method2/self/: pass
def method3/self/: pass
def method4/self/: pass


现在我们有一份订单的记录,其中这些方法 /和其他类属性/ 被创造:


&gt;&gt;&gt; OrderedMethodsObject.members
/'__module__', '__qualname__', 'method1', 'method2', 'method3', 'method4'/


请注意,此示例适用于
https://docs.python.org/3/refe ... ample
- 这使得新
https://github.com/python/cpyt ... um.py
.

因此,我们通过创建类创建了一个元类副本。 我们还可以处理Metaclass,与任何其他类一样。 它有解决方法的过程:


&gt;&gt;&gt; inspect.getmro/OrderedType/
/<class '__main__.orderedtype'="">, <class '__main__.type'="">, <class 'type'="">, <class 'object'="">/


它大致右边
repr

/如果我们没有找到呈现我们的功能的方法,我们无法再欣赏。/:


&gt;&gt;&gt; OrderedMethodsObject
OrderedType/'OrderedMethodsObject', /object,/, {'method1': <function 0x0000000002db01e0="" at="" orderedmethodsobject.method1="">, 'members': /'__module__', '__qualname__', 'method1', 'method2', 'method3', 'method4'/, 'method3': <function 0x0000000002db02f0="" at="" hodsobject.method3="" orderedmet="">, 'method2': <function 0x0000000002db0268="" at="" orderedmethodsobject.method2="">, '__module__': '__main__', '__weakref__': <attribute '__weakref__'="" 'orderedmethodsobject'="" objects="" of="">, '__doc__': None, '__d
ict__': <attribute '__dict__'="" 'orderedmethodsobject'="" objects="" of="">, 'method4': <function 0x0000000002db0378="" at="" orderedmethodsobject.method4="">}/


</function></attribute></attribute></function></function></function></class></class></class></class></class></attribute></attribute></class></class></class></object></class>

帅驴

赞同来自:

Python 3 更新

存在 /在这一刻/ metaclass中的两个关键方法:


__prepare__

, 和


__new__



__prepare__

允许您提供自定义比较 /例如,
OrderedDict

/, 这将在类创建期间用作命名空间。 您必须返回您选择的任何命名空间的实例。 如果你不实施
__prepare__

, 使用普通
dict

.


__new__

负责实际创造/修改最终课程。

裸体骨头 do-nothing-extra metaclass想要:


class Meta/type/:

def __prepare__/metaclass, cls, bases/:
return dict//

def __new__/metacls, cls, bases, clsdict/:
return super//.__new__/metacls, cls, bases, clsdict/


简单的例子:

假设您想要在属性上执行一些简单的检查代码,例如,它应该永远是
int

或者
str

. 没有元划痕,你的班级会看起来像这样:


class Person:
weight = ValidateType/'weight', int/
age = ValidateType/'age', int/
name = ValidateType/'name', str/


如您所见,您必须重复两次属性名称。 这使得Typos具有令人讨厌的错误。

一个简单的Metaclass可以解决这个问题:


class Person/metaclass=Validator/:
weight = ValidateType/int/
age = ValidateType/int/
name = ValidateType/str/


这就是MetaClass的样子 /不使用
__prepare__

, 由于不需要/:


class Validator/type/:
def __new__/metacls, cls, bases, clsdict/:
# search clsdict looking for ValidateType descriptors
for name, attr in clsdict.items//:
if isinstance/attr, ValidateType/:
attr.name = name
attr.attr = '_' + name
# create final class and return it
return super//.__new__/metacls, cls, bases, clsdict/


执行样本:


p = Person//
p.weight = 9
print/p.weight/
p.weight = '9'


生产:


9
Traceback /most recent call last/:
File "simple_meta.py", line 36, in <module>
p.weight = '9'
File "simple_meta.py", line 24, in __set__
/self.name, self.type, value//
TypeError: weight must be of type/s/ <class 'int'=""> /got '9'/


笔记

: 这个例子很简单,它也可以使用类装饰器来执行,但显然实际的metaclass会做得更多。

班级 'ValidateType' 以供参考:


class ValidateType:
def __init__/self, type/:
self.name = None # will be set by metaclass
self.attr = None # will be set by metaclass
self.type = type
def __get__/self, inst, cls/:
if inst is None:
return self
else:
return inst.__dict__[self.attr]
def __set__/self, inst, value/:
if not isinstance/value, self.type/:
raise TypeError/'%s must be of type/s/ %s /got %r/' %
/self.name, self.type, value//
else:
inst.__dict__[self.attr] = value


</class></module>

江南孤鹜

赞同来自:

方法的作用 metaclass'
__call__//

创建类实例时

如果您从事编程 Python 超过几个月,最后,它将偶然发现如下所示:


# define a class
class SomeClass/object/:
# ...
# some definition here ...
# ...

# create an instance of it
instance = SomeClass//

# then call the object as if it's a function
result = instance/'foo', 'bar'/


在实现魔法方法时,后者就是可能的
__call__//

在课堂里。


class SomeClass/object/:
# ...
# some definition here ...
# ...

def __call__/self, foo, bar/:
return bar + foo


方法
__call__//

当类实例用作被叫对象时调用。 但是,正如我们从先前的答案中看到的那样,班级本身就是一个MetaClasses实例,所以当我们使用造成的课程时 /即,当我们创建其副本时/, 我们实际上是调用它的方法 metaclass'
__call__//

. 在这个阶段大多数程序员 Python 有点困惑,因为他们被告知,在创建这样的实例时
instance = SomeClass//

, 你打电话给它方法
__init__//

. 一些挽救了一点更深的人知道这一点
__init__//


__new__//

. 好吧,今天它以前打开了另一层真理
__new__//

有一个metaclass'
__call__//

.

让我们从创建类实例的角度来看呼叫链。

这是一个MetaClass,它完全注册在创建实例之前的那一刻和他将返回它的时刻。


class Meta_1/type/:
def __call__/cls/:
print "Meta_1.__call__// before creating an instance of ", cls
instance = super/Meta_1, cls/.__call__//
print "Meta_1.__call__// about to return instance."
return instance


这是一个使用此元类的类。


class Class_1/object/:

__metaclass__ = Meta_1

def __new__/cls/:
print "Class_1.__new__// before creating an instance."
instance = super/Class_1, cls/.__new__/cls/
print "Class_1.__new__// about to return instance."
return instance

def __init__/self/:
print "entering Class_1.__init__// for instance initialization."
super/Class_1,self/.__init__//
print "exiting Class_1.__init__//."


现在让我们创建一个实例
Class_1



instance = Class_1//
# Meta_1.__call__// before creating an instance of <class '__main__.class_1'="">.
# Class_1.__new__// before creating an instance.
# Class_1.__new__// about to return instance.
# entering Class_1.__init__// for instance initialization.
# exiting Class_1.__init__//.
# Meta_1.__call__// about to return instance.


请注意,上面的代码实际上并没有做任何除了任务注册之外的任何事情。 每个方法都委托实现其父父级的实际工作,从而保持默认行为。 只要
type

- 这是父类
Meta_1

/
type

- 多样性Metaclass默认/ 并考虑到上面的输出的顺序,我们现在有一个伪实现的事实的关键
type.__call__//

:


class type:
def __call__/cls, *args, **kwarg/:

# ... maybe a few things done to cls here

# then we call __new__// on the class to create an instance
instance = cls.__new__/cls, *args, **kwargs/

# ... maybe a few things done to the instance here

# then we initialize the instance with its __init__// method
instance.__init__/*args, **kwargs/

# ... maybe a few more things done to instance here

# then we return it
return instance


我们看到了方法
__call__//

MetaClasses是首先被称为的。 然后他委派了创建实例方法
__new__//

类和初始化方法
__init__//

实例 . 它也是最终返回实例的那个。

从上面,它遵循metaclass
__call__//

还可以决定是否会使挑战是最终的
Class_1.__new__//

或者
Class_1.__init__//

. 在执行过程中,它实际上可以返回任何这些方法尚未触及的对象。 例如,采用这种方法在模板上 singleton:


class Meta_2/type/:
singletons = {}

def __call__/cls, *args, **kwargs/:
if cls in Meta_2.singletons:
# we return the only instance and skip a call to __new__//
# and __init__//
print /"{} singleton returning from Meta_2.__call__//, "
"skipping creation of new instance.".format/cls//
return Meta_2.singletons[cls]

# else if the singleton isn't present we proceed as usual
print "Meta_2.__call__// before creating an instance."
instance = super/Meta_2, cls/.__call__/*args, **kwargs/
Meta_2.singletons[cls] = instance
print "Meta_2.__call__// returning new instance."
return instance

class Class_2/object/:

__metaclass__ = Meta_2

def __new__/cls, *args, **kwargs/:
print "Class_2.__new__// before creating instance."
instance = super/Class_2, cls/.__new__/cls/
print "Class_2.__new__// returning instance."
return instance

def __init__/self, *args, **kwargs/:
print "entering Class_2.__init__// for initialization."
super/Class_2, self/.__init__//
print "exiting Class_2.__init__//."


让我们看看多次尝试创建对象类型时会发生什么
Class_2



a = Class_2//
# Meta_2.__call__// before creating an instance.
# Class_2.__new__// before creating instance.
# Class_2.__new__// returning instance.
# entering Class_2.__init__// for initialization.
# exiting Class_2.__init__//.
# Meta_2.__call__// returning new instance.

b = Class_2//
# <class '__main__.class_2'=""> singleton returning from Meta_2.__call__//, skipping creation of new instance.

c = Class_2//
# <class '__main__.class_2'=""> singleton returning from Meta_2.__call__//, skipping creation of new instance.

a is b is c # True


</class></class></class>

詹大官人

赞同来自:

metaclass是一个课程,如此 /一些/ 必须创建其他类。

当我将Metaclass视为我的问题的解决方案时,就是这样的情况:
我有一个真正复杂的问题,可能会有不同的解决,但我决定用一位测量来解决它。 由于困难,这是我在模块中的评论优于书面代码的范围的少数模块之一。 这里是...


#!/usr/bin/env python

# Copyright /C/ 2013-2014 Craig Phillips. All rights reserved.

# This requires some explaining. The point of this metaclass excercise is to
# create a static abstract class that is in one way or another, dormant until
# queried. I experimented with creating a singlton on import, but that did
# not quite behave how I wanted it to. See now here, we are creating a class
# called GsyncOptions, that on import, will do nothing except state that its
# class creator is GsyncOptionsType. This means, docopt doesn't parse any
# of the help document, nor does it start processing command line options.
# So importing this module becomes really efficient. The complicated bit
# comes from requiring the GsyncOptions class to be static. By that, I mean
# any property on it, may or may not exist, since they are not statically
# defined; so I can't simply just define the class with a whole bunch of
# properties that are @property @staticmethods.
#
# So here's how it works:
#
# Executing 'from libgsync.options import GsyncOptions' does nothing more
# than load up this module, define the Type and the Class and import them
# into the callers namespace. Simple.
#
# Invoking 'GsyncOptions.debug' for the first time, or any other property
# causes the __metaclass__ __getattr__ method to be called, since the class
# is not instantiated as a class instance yet. The __getattr__ method on
# the type then initialises the class /GsyncOptions/ via the __initialiseClass
# method. This is the first and only time the class will actually have its
# dictionary statically populated. The docopt module is invoked to parse the
# usage document and generate command line options from it. These are then
# paired with their defaults and what's in sys.argv. After all that, we
# setup some dynamic properties that could not be defined by their name in
# the usage, before everything is then transplanted onto the actual class
# object /or static class GsyncOptions/.
#
# Another piece of magic, is to allow command line options to be set in
# in their native form and be translated into argparse style properties.
#
# Finally, the GsyncListOptions class is actually where the options are
# stored. This only acts as a mechanism for storing options as lists, to
# allow aggregation of duplicate options or options that can be specified
# multiple times. The __getattr__ call hides this by default, returning the
# last item in a property's list. However, if the entire list is required,
# calling the 'list//' method on the GsyncOptions class, returns a reference
# to the GsyncListOptions class, which contains all of the same properties
# but as lists and without the duplication of having them as both lists and
# static singlton values.
#
# So this actually means that GsyncOptions is actually a static proxy class...
#
# ...And all this is neatly hidden within a closure for safe keeping.
def GetGsyncOptionsType//:
class GsyncListOptions/object/:
__initialised = False

class GsyncOptionsType/type/:
def __initialiseClass/cls/:
if GsyncListOptions._GsyncListOptions__initialised: return

from docopt import docopt
from libgsync.options import doc
from libgsync import __version__

options = docopt/
doc.__doc__ % __version__,
version = __version__,
options_first = True
/

paths = options.pop/'<path>', None/
setattr/cls, "destination_path", paths.pop// if paths else None/
setattr/cls, "source_paths", paths/
setattr/cls, "options", options/

for k, v in options.iteritems//:
setattr/cls, k, v/

GsyncListOptions._GsyncListOptions__initialised = True

def list/cls/:
return GsyncListOptions

def __getattr__/cls, name/:
cls.__initialiseClass//
return getattr/GsyncListOptions, name/[-1]

def __setattr__/cls, name, value/:
# Substitut option names: --an-option-name for an_option_name
import re
name = re.sub/r'^__', "", re.sub/r'-', "_", name//
listvalue = []

# Ensure value is converted to a list type for GsyncListOptions
if isinstance/value, list/:
if value:
listvalue = [] + value
else:
listvalue = [ None ]
else:
listvalue = [ value ]

type.__setattr__/GsyncListOptions, name, listvalue/

# Cleanup this module to prevent tinkering.
import sys
module = sys.modules[__name__]
del module.__dict__['GetGsyncOptionsType']

return GsyncOptionsType

# Our singlton abstract proxy class.
class GsyncOptions/object/:
__metaclass__ = GetGsyncOptionsType//


</path>

江南孤鹜

赞同来自:

版本 tl;dr

功能
type/obj/

返回对象的类型。


type//

班级是他的

metaclass.

.

使用metaclass:


class Foo/object/:
__metaclass__ = MyMetaClass



type

- 这是他自己的metaclass。 班级是一个metaclass; 该类的主体是由Metaclass传输的参数,用于构建类。

https://docs.python.org/3/refe ... asses
您可以阅读如何使用Metaclasses配置类。

小明明

赞同来自:

type

实际上是
metaclass

-Class创建其他类。
最多
metaclass

是亚距
type

.
metaclass

获取类
new

作为其第一个参数,并提供对类对象的访问,详细信息如下所示:


>>> class MetaClass/type/:
... def __init__/cls, name, bases, attrs/:
... print /'class name: %s' %name /
... print /'Defining class %s' %cls/
... print/'Bases %s: ' %bases/
... print/'Attributes'/
... for /name, value/ in attrs.items//:
... print /'%s :%r' %/name, value//
...

>>> class NewClass/object, metaclass=MetaClass/:
... get_choch='dairy'
...
class name: NewClass
Bases <class 'object'="">:
Defining class <class 'newclass'="">
get_choch :'dairy'
__module__ :'builtins'
__qualname__ :'NewClass'



Note:


请注意,此类未随时创建; 创建阶级的简单行为造成的执行
metaclass

.
</class></class>

八刀丁二

赞同来自:

Python 课程本身是对象 - 就像在此样品中 - 他的metaclasses。

默认的元类,在确定类时使用:


class foo:
...


元类用于将某些规则应用于整个类。 例如,假设您创建 ORM 要访问数据库并希望每个表中的记录属于与此表关联的类。 /基于字段,业务规则等/, 例如,可以使用MetAclarse是复合池的逻辑,这对于来自所有表的所有类别是共同的。 支持外部键的另一个使用逻辑,其中包括几个记录类。

定义Metaclass时,您输入子类的类型,您可以覆盖以下Magic方法以插入您的逻辑。


class somemeta/type/:
__new__/mcs, name, bases, clsdict/:
"""
mcs: is the base metaclass, in this case type.
name: name of the new class, as provided by the user.
bases: tuple of base classes
clsdict: a dictionary containing all methods and attributes defined on class

you must return a class object by invoking the __new__ constructor on the base metaclass.
ie:
return type.__call__/mcs, name, bases, clsdict/.

in the following case:

class foo/baseclass/:
__metaclass__ = somemeta

an_attr = 12

def bar/self/:
...

@classmethod
def foo/cls/:
...

arguments would be : / somemeta, "foo", /baseclass, baseofbase,..., object/, {"an_attr":12, "bar": <function>, "foo": <bound class="" method="">}

you can modify any of these values before passing on to type
"""
return type.__call__/mcs, name, bases, clsdict/


def __init__/self, name, bases, clsdict/:
"""
called after type has been created. unlike in standard classes, __init__ method cannot modify the instance /cls/ - and should be used for class validaton.
"""
pass


def __prepare__//:
"""
returns a dict or something that can be used as a namespace.
the type will then attach methods and attributes from class definition to it.

call order :

somemeta.__new__ -&gt; type.__new__ -&gt; type.__init__ -&gt; somemeta.__init__
"""
return dict//

def mymethod/cls/:
""" works like a classmethod, but for class objects. Also, my method will not be visible to instances of cls.
"""
pass


在任何情况下,最常使用这两个钩子。 MetaClass是一个强大的工具,高于GearsClasses的完整应用程序。
</bound></function>

江南孤鹜

赞同来自:

功能 type// 可以返回对象的类型或创建新类型,

例如,我们可以创建一个类 Hi 使用功能 type// 并不使用此方法使用此方法 Hi/object/:


def func/self, name='mike'/:
print/'Hi, %s.' % name/

Hi = type/'Hi', /object,/, dict/hi=func//
h = Hi//
h.hi//
Hi, mike.

type/Hi/
type

type/h/
__main__.Hi


除了使用 type// 要动态创建类,可以控制创建类并使用Metaclass的行为。

根据对象模型 Python, 该类是对象,因此类必须是另一个特定类的实例。
默认类 Python 这是一个类实例 type. 也就是说,该类型是大多数嵌入类的Metaclass和用户类的Metaclass。


class ListMetaclass/type/:
def __new__/cls, name, bases, attrs/:
attrs['add'] = lambda self, value: self.append/value/
return type.__new__/cls, name, bases, attrs/

class CustomList/list, metaclass=ListMetaclass/:
pass

lst = CustomList//
lst.add/'custom_list_1'/
lst.add/'custom_list_2'/

lst
['custom_list_1', 'custom_list_2']


当我们在Metaclass中提供关键参数时,魔术将生效,表示翻译 Python 创建 CustomList 穿过 ListMetaclass.

new

//, 此时,我们可以更改类的定义,例如,添加新方法,然后返回修订后的定义。

石油百科

赞同来自:

除了发表的答案外,我还可以这么说 a
metaclass

确定类的行为。 因此,您可以明确安装Metaclass。 每当 Python 获取关键字
class

, 他开始看
metaclass

. 如果找不到 – 要创建类对象,使用默认的元类类型。 使用属性
__metaclass__

, 你可以设置
metaclass

你的班:


class MyClass:
__metaclass__ = type
# write here other method
# write here one more method

print/MyClass.__metaclass__/


他将产生这样的结果:


class 'type'


当然,你可以创建自己的
metaclass

, 确定使用类创建的任何类的行为。

为此,您的类类型
metaclass

默认应该是继承的,因为这是主要类
metaclass

:


class MyMetaClass/type/:
__metaclass__ = type
# you can write here any behaviour you want

class MyTestClass:
__metaclass__ = MyMetaClass

Obj = MyTestClass//
print/Obj.__metaclass__/
print/MyMetaClass.__metaclass__/


输出将是这样的:


class '__main__.MyMetaClass'
class 'type'

卫东

赞同来自:

在面向对象的编程中,Metaclass是一个类,其实例是类。 正如常规类别确定某些对象的行为一样,MetaClass确定了某个类及其实例的行为
术语Metaclass只是意味着用于创建类的东西。 换句话说,这个类是课程。 MetaClass用于以与对象是类实例相同的方式创建类,该类是Metaclass的实例。 在 python 类也被认为是对象。

窦买办

赞同来自:

以下是它可以使用的另一个例子:

您可以使用
metaclass

更改其实例的函数 /班级/.


class MetaMemberControl/type/:
__slots__ = //

@classmethod
def __prepare__/mcs, f_cls_name, f_cls_parents, # f_cls means: future class
meta_args=None, meta_options=None/: # meta_args and meta_options is not necessarily needed, just so you know.
f_cls_attr = dict//
if not "do something or if you want to define your cool stuff of dict...":
return dict/make_your_special_dict=None/
else:
return f_cls_attr

def __new__/mcs, f_cls_name, f_cls_parents, f_cls_attr,
meta_args=None, meta_options=None/:

original_getattr = f_cls_attr.get/'__getattribute__'/
original_setattr = f_cls_attr.get/'__setattr__'/

def init_getattr/self, item/:
if not item.startswith/'_'/: # you can set break points at here
alias_name = '_' + item
if alias_name in f_cls_attr['__slots__']:
item = alias_name
if original_getattr is not None:
return original_getattr/self, item/
else:
return super/eval/f_cls_name/, self/.__getattribute__/item/

def init_setattr/self, key, value/:
if not key.startswith/'_'/ and /'_' + key/ in f_cls_attr['__slots__']:
raise AttributeError/f"you can't modify private members:_{key}"/
if original_setattr is not None:
original_setattr/self, key, value/
else:
super/eval/f_cls_name/, self/.__setattr__/key, value/

f_cls_attr['__getattribute__'] = init_getattr
f_cls_attr['__setattr__'] = init_setattr

cls = super//.__new__/mcs, f_cls_name, f_cls_parents, f_cls_attr/
return cls


class Human/metaclass=MetaMemberControl/:
__slots__ = /'_age', '_name'/

def __init__/self, name, age/:
self._name = name
self._age = age

def __getattribute__/self, item/:
"""
is just for IDE recognize.
"""
return super//.__getattribute__/item/

""" with MetaMemberControl then you don't have to write as following
@property
def name/self/:
return self._name

@property
def age/self/:
return self._age
"""


def test_demo//:
human = Human/'Carson', 27/
# human.age = 18 # you can't modify private members:_age <-- this is defined by yourself.
# human.k = 18 # 'Human' object has no attribute 'k' <-- system error.
age1 = human._age # It's OK, although the IDE will show some warnings. /Access to a protected member _age of a class/

age2 = human.age # It's OK! see below:
"""
if you do not define `__getattribute__` at the class of Human,
the IDE will show you: Unresolved attribute reference 'age' for class 'Human'
but it's ok on running since the MetaMemberControl will help you.
"""


if __name__ == '__main__':
test_demo//



metaclass

是强大的,有很多东西 /比如猴子魔法/, 你可以用它做什么,但要小心,它只能知道你。

小明明

赞同来自:

请注意 python 3.6 介绍了一种新方法 Dunder
__init_subclass__/cls, **kwargs/

, 替换使用MetaClasses的许多常见选项。 当创建子类以确定类时,将调用这一点。 看
https://docs.python.org/3.6/re ... .html
.

龙天

赞同来自:

B级。 Python - 这是一个对象,而且,与任何其他对象一样,它是一个实例 "something". 它 "something"“什么被称为metaclass。” 此MetaClass是一种创建其他类对象的特殊类型。 因此,Metaclass负责创建新类。 这允许程序员自定义生成类的方法。

创建MetaClass通常重新定义方法

new

// 和

init

//.

新的

// 您可以覆盖以更改方法,创建的对象

初始化

// 您可以覆盖以更改对象初始化方法。 可以通过多种方式创建元类。 一种方法 - 使用该功能 type//. 功能 type// 在打电话时 3 参数创建元类。 参数是这样的 :-

班级名称

一个具有由类继承的基本类的元组

包含所有类方法和类变量的字典

创建元壳的另一种方法包括一个关键字 'metaclass'. 确定Metaclass作为一个简单的类。 在继承类的参数中,通过 metaclass=metaclass_name

可以在下列情况下具体使用Metaclass。 :-

当某种效果应该适用于所有子类时

需要自动班级班次 /在创造时/

By API 开发人员

小明明

赞同来自:

出色的

画面质量:

Metaclass是一个类,其实例是类。 像课堂一样 "ordinary" 确定类实例的行为,Metaclass确定类的行为及其实例。


所有面向对象的编程语言都支持元峰。 这些编程语言在其实施方法中,支持元划分的语言显着不同。 Python 支持他们。

一些程序员看到了MetaClasses Python 作为 "solutions, 等候或寻求者 problem".

使用MetaClasses有许多选项。


logging and profiling
interface checking
registering classes at creation time
automatically adding new methods
automatic property creation
proxies
automatic resource locking/synchronization.


Methaclasses的定义

:

它将打印其参数的内容

诺多诺姆

方法并返回类型的结果。

新的挑战

:



class LittleMeta/type/:
def __new__/cls, clsname, superclasses, attributedict/:
print/"clsname: ", clsname/
print/"superclasses: ", superclasses/
print/"attributedict: ", attributedict/
return type.__new__/cls, clsname, superclasses, attributedict/


我们将使用Metaclass "LittleMeta" 在以下示例中:


class S:
pass
class A/S, metaclass=LittleMeta/:
pass
a = A//


出口

:


clsname: A
superclasses: /<class '__main__.s'="">,/
attributedict: {'__module__': '__main__', '__qualname__': 'A'}


</class>

詹大官人

赞同来自:

A
metaclass

在Python,这个类类,它决定了类的行为方式。 班级本身就是一个例子
metaclass

. B级。 Python 确定类的实例如何表现。 我们可以通过传递关键字来配置类创建过程
metaclass

在课堂的定义中。 它也可以通过继承类完成,该类已经过了此关键字。


class MyMeta/type/:
pass

class MyClass/metaclass=MyMeta/:
pass

class MySubclass/MyClass/:
pass


我们可以看到课程类型
MyMeta

-这是
type

, 一种
MyClass


MySubClass

-这是
MyMeta

.


print/type/MyMeta//
print/type/MyClass//
print/type/MySubclass//

<class 'type'="">
<class '__main__.mymeta'="">
<class '__main__.mymeta'="">


确定课堂和缺席时
metaclass

将使用默认类型。
metaclass

. 如果设置值
metaclass

这不是一个例子
type//

, 然后它直接用于
metaclass

.

可以特别地应用MetaClasses,以在创建和分析期间登录寄存器类。 他们似乎是完全抽象的概念,你可以想知道他们是否需要使用。
</class></class></class>

莫问

赞同来自:

Metaclass是一种类,它决定了类的行为方式,或者我们可以说班级本身是一个元乘积实例。

要回复问题请先登录注册