>>> 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'="">
>>> def echo/o/:
... print/o/
...
>>> echo/ObjectCreator/ # you can pass a class as a parameter
<class '__main__.objectcreator'="">
>>> print/hasattr/ObjectCreator, 'new_attribute'//
False
>>> ObjectCreator.new_attribute = 'foo' # you can add attributes to a class
>>> print/hasattr/ObjectCreator, 'new_attribute'//
True
>>> print/ObjectCreator.new_attribute/
foo
>>> ObjectCreatorMirror = ObjectCreator # you can assign a class to a variable
>>> print/ObjectCreatorMirror.new_attribute/
foo
>>> print/ObjectCreatorMirror///
<__main__.ObjectCreator object at 0x8997b4c>
动态创造课程
由于类是对象,您可以像任何其他对象一样创建它们。
首先,您可以使用功能创建一个类
class
:
>>> 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
...
>>> MyClass = choose_class/'foo'/
>>> print/MyClass/ # the function returns a class, not an instance
<class '__main__.foo'="">
>>> print/MyClass/// # you can create an object from this class
<__main__.Foo object at 0x89c6d4c>
>>> MyShinyClass = type/'MyShinyClass', //, {}/ # returns a class object
>>> print/MyShinyClass/
<class '__main__.myshinyclass'="">
>>> print/MyShinyClass/// # create an instance with the class
<__main__.MyShinyClass object at 0x8997cec>
事实上,它可以是任何造成的,它不必是 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'
# 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/:
...
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
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/, {}/
# 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__
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//
# 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'
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 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
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.
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
# 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__
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 ]
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.
@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 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/
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.
"""
22 个回复
裸奔
赞同来自:
在处理MetaClasses之前,您需要通过主课程进行 Python. 和 Python 对从语言借用的课程有一个非常奇特的想法 Smalltalk.
在大多数语言中,类只是描述如何创建对象的代码的片段。 这也是一种真理 Python :
但课程不仅仅是 Python. 类也是对象。
是的,对象。
使用关键字后
, Python 执行它并创建
OBJECT. 操作说明
创建一个名称的对象 "ObjectCreator".
这个对象 /班级/ 它能够创建对象 /套/,
这就是为什么他是一堂课
.
但这仍然是一个对象,因此:
您可以将其分配给变量
你可以复制它
您可以为其添加属性。
您可以将其作为函数参数传递。
例如:
动态创造课程
由于类是对象,您可以像任何其他对象一样创建它们。
首先,您可以使用功能创建一个类
:
但这不是那么动态,因为你仍然必须自己写整个班级。
由于类是对象,因此必须由某些东西生成。
使用关键字时
, Python 自动创建此对象。 但怎么样?
大多数事情都在 Python, 它让您有机会手动进行。
记住这个功能
? 旧的好功能让您了解什么
类型对象:
出色地,
http://docs.python.org/2/libra ... 3type
有一个完全不同的能力,它也可以在飞行中创造课程。
可以接受类描述作为参数
和返回课程。
/我知道这是愚蠢的,相同的功能可以有两个完全不同的用途,具体取决于您传递给它的参数。 这是由于反向的问题
兼容B. Python/
以这种方式工作:
在哪里:
: 班级名称
: 父级成熟 /继承可以是空的/
: 字典包含属性名称和值
, 例如:
因此,它可以手动创建:
您会注意到我们使用 "MyShinyClass" 作为班级名称
作为用于存储对类的引用的变量。 它们可以不同
但没有理由使一切复杂化。
采用字典来确定类属性。 所以:
可以翻译:
并用作常规课程:
当然,你可以继承他,所以:
将:
最终,您将想向您的课程添加方法。 刚确定功能
使用相应的签名并将其分配为属性。
您可以在动态类创建后添加更多方法,就像将方法添加到通常创建的类对象一样。
你看看我们去哪里:在 Python 类是对象,您可以动态地创建一个类。
这是 , 他在做什么 Python, 使用关键字时
, 他用一个metaclass做了它。
什么是metaClasses. /最后/
metaClasses是 'stuff', 它创造了课程。
您定义类以创建对象,对吗?
但我们了解到课程 Python 是对象。
嗯,MetaClasses是创造这些物体的原因。 他们是课程课程
你可以以这种方式展示它们:
你见过这个
允许您做那样的事情:
这是因为功能
事实上,这是一个metaclass。
-这是
metaclass,哪个 Python 用于在幕后创建所有类。
现在你很惊讶为什么,该死的,它是用小写的,而不是
?
嗯,我想 , 这是一个一致性的问题
, 创造的课程
字符串对象
一个创建整数对象的类。
-这是
只需创建类对象的类。
您可以通过检查该属性来验证这一点
.
一切,我的意思是一切都是对象 Python. 这包括 ints,
行,函数和课程。 所有这些都是物体。 和所有人
是从课堂上创建的:
那么是什么
任何人
?
因此,Metaclass只是一种创建类对象的材料。
你可以称之为 'class factory', 如果你想。
- 这是使用的内置Metaclass Python, 但是,当然,您可以创建自己的。
自己的metaclass。
属性
http://docs.python.org/2/refer ... ass__
在 Python 2 您可以添加属性
写一堂课时 /有关语法,请参阅以下部分 Python 3/:
如果你这样做,那么 Python 将使用metaclass创建一个类
.
仔细,很难。
首先你写道
, 但是类对象
尚未创建
心里。
Python 会发现
在课堂定义中。 如果他找到他
它将使用它来创建一类对象。
. 如果不是,它将使用
创建一个类。
几次阅读它。
当你这样做时:
Python 执行以下操作:
有一个属性
在
?
如果是,则在内存中创建类对象 /我说课堂对象,留在这里/ 名称
, 使用什么
.
如果一个 Python 找不到
, 他会发现
在水平 MODULE 并试图做同样的事情 /但仅适用于不继承任何东西的课程,大多是旧风格的阶级/.
然后,如果他找不到任何东西
, 它将使用自己的metaclass
/第一个父母/ /默认情况下可以
/ 创建类对象。
在这里谨慎归功
不是继承,父母元 /
/ 将。 如果一个
二手归因
, 谁创造了
从
/但不是
/, 子类不会继承此行为。
现在主要问题是你可以投入
?
答案是:可以创建一个类的东西。
什么可以创造一个课程?
, 或所有的子类或使用它。
Metachellable B. Python 3
MetaClass安装语法已更改 Python 3:
, 这是属性
不再用于基本类列表中的一个关键参数。
然而,MetaClasses的行为仍然存在
https://www.python.org/dev/peps/pep-3115/
最多。 .
有一件事添加到metablasses中 python 3, 正是您还可以将属性传输为Metaclass中的关键字参数,例如:
阅读下面的部分 python 他和它一起调查。
自定义元壳
MetaClass自动课程变更的主要目标
创建它时。
通常你这样做 APIs, 您想要创建对应的类的位置
当前的上下文。
想象一个愚蠢的例子,当你决定模块中的所有类时
必须在大写中写入自己的属性。 有几种方式
做到这一点,但其中一个是安装
在模块级别。
因此,将使用此MetAclarse创建此模块的所有类,
我们只需要说一个元队将所有属性转换为大写。
幸运的是,
事实上,它可以是任何造成的,它不必是 a
正式的课堂 /我知道了 'class' 他的名字不应该是
班级,让我们说......但它很有用/.
因此,我们将从使用该函数的简单示例开始。
让我们检查:
现在让我们这样做,但是使用一个真正的metaclasses:
让我们重写前述,但现在有更短的变化的变量名,当我们知道他们的意思时:
您可能会注意到额外的论点
. 有
它没有什么特别的:
始终获得一个类,其中它被定义为第一个参数。 就像你一样
对于接收实例作为第一个参数的传统方法,或类方法的定义类。
但这并不是正确的 OOP. 我们称之为
直接,而不是覆盖或呼叫父母
. :
我们可以让它仍然清洁 , 使用
, 什么促进遗产 /因为是的,您可能拥有从类型继承的MetaClass内继承的甲烷类/:
哦,在 python 3, 例如,如果使用关键字参数进行此调用,例如:
它在Metaclass中翻译成用于使用它:
就这样。 事实上,Getablasses没有任何关于。
使用甲烷的代码复杂性的原因不是那样
至于MetaLlates,它是因为您通常使用MetaClasses来执行erversions
, 依靠内省 , 操纵遗传 vars, 如
等等。
实际上,MetaClasses对黑魔法特别有用,这意味着
, 以及复杂的东西。 但是自己,他们很简单:
拦截创建一个类
改变类
返回更改的类
为什么你使用元舱的类而不是函数?
只要
可以采取任何叫做的对象,为什么要使用该类
由于这显然更困难了?
为此有几个原因:
意图是明确的。 当你读书的时候
, 你懂
, 这是如此
您可以使用 OOP. Metaclass可以从甲烷来源,重新定义父母方法。 MetaClasses甚至可以使用MetaClasses。
如果您指定了MetaClass类,则将类子类将是其MetAclarse的副本,但不使用MetaClass函数。
你可以更好地训练你的代码。 你永远不会使用metaclasses
琐碎的,如上面的例子。 这通常是为了复杂的东西。 可用性
在一个班级中创建多种方法和组的能力非常有用
促进读取代码。
你可以坚持
,
和
. 这将允许
你做不同的事情。 即使你通常可以全部做到这一切
,
有些人只是使用更舒服
.
他们被称为Methaclasses,该死的! 它应该意味着什么!
你为什么需要MetaClasses?
现在是主要问题。 为什么你需要使用一些不可征收的函数受到错误?
好吧,通常你不是:
metaClasses是深度魔法
99% 用户永远不应该担心它。
如果你想知道他们是否需要你,
你不这样做 /真正的人
需要他们,充满信心地知道这一点
他们需要它们,不需要
解释为什么/.
Python 格鲁鲁·蒂姆彼得斯
metaclarse的主要使用是创作 API. 这个典型的例子是 Django ORM. 这允许您确定这样的内容:
但如果你这样做:
他不会回归物体
. 他会回来
甚至可以直接从数据库中取出它。
这是可能的,因为
确定
和
使用一些将转向的魔法
, 您刚用简单的运营商定义
, 在数据库字段的复杂钩子中。
Django 让一些复杂的简单,曝光简单 API
并使用MetaClasses,来自此的娱乐代码 API, 做实际的工作
对于鳞片。
最后一个字
首先,您知道类是可以创建实例的对象。
好吧,事实上,课程本身是副本。 关于metaclasses。
一切都是对象 Python, 所有这些都是课程的实例
, 一份副本的元峰。
除了
.
- 它实际上是它自己的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>
喜特乐
赞同来自:
而在 Python 您可以使用任意尝试对象进行MetaClasses。 /如图所示 Jerub/, 最好的方法是使它成为实际的课程。
- 这是一个普通的metaclass Python.
本身,它是类,这是他自己的类型。 你将无法重新创建类似的东西
纯V. Python, 但 Python 有点欺骗。 创建自己的metaclass Python, 你真的只想要一个子类
.
Metaclass最常被用作班级工厂。 创建一个调用类的对象时, Python 创造一个新的课程 /执行操作员时 'class'/, 由metaclass引起的。 因此,与常规方法组合
和
metaClasses允许您执行 'extra things' 例如,在创建类时,在任何注册表中注册一个新类或替换完全不同的类。
当运营商时
表演, Python 首先执行操作员的主体
作为常规代码块。 结果名称空间 /dict/ 包含属性 class-to-be. 通过查看基本类来确定metaclass class-to-be /遗传是元壳/, attributa.
class-to-be /如果是的话/ 或全局变量
. 然后使用名称,数据库和类属性调用metaclass以创建其实例。
但是,MetaClasses实际确定
一种
班级,不只是为他的工厂,所以你可以和他们做得更多。 例如,您可以确定Metaclass中的常用方法。 这些元方法喜欢 classmethods 在没有实例的情况下可以在课堂上调用它们,但它们也不喜欢 classmethods 他们不能由班级实例引起的事实。
- 这是Metaclass中的方法的示例
. 您还可以确定通常的方法。 'magic', 如那个
,
和
, 实现或更改类行为。
以下是位和块的聚合示例:
喜特乐
赞同来自:
MetaClasses是一种秘密酱 'class' 工作。 调用新样式对象的默认元类。 'type'.
接受的金属蹄类 3 争论。 "
姓名
", "
基础
" 和 "
迪克
"
这是神秘开始的地方。 请参阅从此示例的类定义中获取的名称,foundation和dict。
让我们定义一个将展示如何的metaclass '
class:
' 导致它。
而现在是一个真正意味着什么的例子,将自动在列表中制作变量 "attributes" 在课堂上建立等 None.
请注意,这个神奇的行为
得到一个metaclass
, 不传输给子类
.
以下是一个更具体的示例,展示了如何子类 'type' 创建MetaClass,在创建类时执行操作。 这很困难:
</type></type>
石油百科
赞同来自:
所有这些是子类
, 然后获取类属性
, 这是写入课程的命令。
莫问
赞同来自:
例如,如果你看看
http://docs.djangoproject.com/ ... dels/
, 他们的定义看起来有点令人困惑。 它看起来好像只定义类的属性:
但是,在执行对象期间 Person 充满了各种有用的方法。 看
http://code.djangoproject.com/ ... se.py
对于一些惊人的甲烷。
小姐请别说爱
赞同来自:
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%.
裸奔
赞同来自:
TLDR: MetaClass以与类创建的相同方式创建并确定类的行为,并确定实例的行为。
伪码:
以上所有人都应该看起来很熟悉。 好吧,它来自哪里
? 这是一个metaclass副本 /也是伪代码/:
在实际代码中,我们可以传输默认的元类,
, 全部 , 我们需要创建一个类实例,我们将获得一个课程:
说话不同
该类指的是实例以与类的Metaclass相同的方式。
当我们创建对象的实例时,我们得到一个实例:
同样,当我们用默认的元类明确定义类时,
, 我们创建了它的实例:
换句话说,一个类是MetaClassa的实例:
第三,metaclass是类类。
写入类定义时和 Python 执行它,它使用Metaclass来创建类对象的实例 /反过来,这将用于创建此类的实例/.
正如我们可以使用类定义要更改对象的用户实例的行为,我们可以使用Metaclasses类定义来更改类对象的行为。
为什么可以使用? 的
https://docs.python.org/3/refe ... ample
:
使用MetaClasses的可能性是无穷无尽的。 调查的一些想法包括日志记录,检查界面,自动委派,自动属性,代理服务器,框架和自动资源 locking/synchronization.
但是,通常建议使用用户,以避免使用MetaClasses而无需很多需求。
每次创建类时都使用Metaclass:
例如,当您编写类定义时,如此
您创建了类对象的实例。
这是在功能上造成的相同的事情
具有适当的参数并分配具有相同名称的变量的结果:
请注意,有些东西会自动添加到
, 也就是说,命名空间:
metaclass.
我们在这两种情况下创建的对象是相等的
.
/课程内容的注意事项
:
存在,因为课程应该知道它们定义的位置,以及
和
存在,因为我们没有定义
- 要是我们
https://coderoad.ru/472000/
我们将在副本中保存一点空间,我们可以禁止
和
, 通过排除它们。 例如:
80 但我分心了。/
我们可以扩展
就像类的任何其他定义一样:
这是默认值
课程:
在编写对象时,我们可以默认做出最有价值的事情之一 Python, - 它给了他一个好的
. 当我们打电话的时候
, 我们了解到有一个很好的考验
, 这也需要平等面团 -
. 下一个简单的实现
和
对于我们类型类型的类的实例,它为我们提供了一个可以改善默认类工作的演示
:
所以现在,当我们使用此元册创建一个对象时,
, 反映在命令提示符上,提供比默认值更少的丑陋视图:
有良好的
, 为类实例定义,我们有更强大的调试代码的能力。 但是,进一步验证
不太可能 /由于函数从默认值计算
/.
预期用途:
空间名称
例如,如果我们想知道类方法创建了哪些顺序,我们可以提供有序 dict 作为类命名空间。 我们会做到
, 哪一个
https://docs.python.org/3/refe ... space
:
并使用:
现在我们有一份订单的记录,其中这些方法 /和其他类属性/ 被创造:
请注意,此示例适用于
https://docs.python.org/3/refe ... ample
- 这使得新
https://github.com/python/cpyt ... um.py
.
因此,我们通过创建类创建了一个元类副本。 我们还可以处理Metaclass,与任何其他类一样。 它有解决方法的过程:
它大致右边
/如果我们没有找到呈现我们的功能的方法,我们无法再欣赏。/:
</function></attribute></attribute></function></function></function></class></class></class></class></class></attribute></attribute></class></class></class></object></class>
帅驴
赞同来自:
存在 /在这一刻/ metaclass中的两个关键方法:
, 和
允许您提供自定义比较 /例如,
/, 这将在类创建期间用作命名空间。 您必须返回您选择的任何命名空间的实例。 如果你不实施
, 使用普通
.
负责实际创造/修改最终课程。
裸体骨头 do-nothing-extra metaclass想要:
简单的例子:
假设您想要在属性上执行一些简单的检查代码,例如,它应该永远是
或者
. 没有元划痕,你的班级会看起来像这样:
如您所见,您必须重复两次属性名称。 这使得Typos具有令人讨厌的错误。
一个简单的Metaclass可以解决这个问题:
这就是MetaClass的样子 /不使用
, 由于不需要/:
执行样本:
生产:
笔记
: 这个例子很简单,它也可以使用类装饰器来执行,但显然实际的metaclass会做得更多。
班级 'ValidateType' 以供参考:
</class></module>
江南孤鹜
赞同来自:
创建类实例时
如果您从事编程 Python 超过几个月,最后,它将偶然发现如下所示:
在实现魔法方法时,后者就是可能的
在课堂里。
方法
当类实例用作被叫对象时调用。 但是,正如我们从先前的答案中看到的那样,班级本身就是一个MetaClasses实例,所以当我们使用造成的课程时 /即,当我们创建其副本时/, 我们实际上是调用它的方法 metaclass'
. 在这个阶段大多数程序员 Python 有点困惑,因为他们被告知,在创建这样的实例时
, 你打电话给它方法
. 一些挽救了一点更深的人知道这一点
有
. 好吧,今天它以前打开了另一层真理
有一个metaclass'
.
让我们从创建类实例的角度来看呼叫链。
这是一个MetaClass,它完全注册在创建实例之前的那一刻和他将返回它的时刻。
这是一个使用此元类的类。
现在让我们创建一个实例
请注意,上面的代码实际上并没有做任何除了任务注册之外的任何事情。 每个方法都委托实现其父父级的实际工作,从而保持默认行为。 只要
- 这是父类
/
- 多样性Metaclass默认/ 并考虑到上面的输出的顺序,我们现在有一个伪实现的事实的关键
:
我们看到了方法
MetaClasses是首先被称为的。 然后他委派了创建实例方法
类和初始化方法
实例 . 它也是最终返回实例的那个。
从上面,它遵循metaclass
还可以决定是否会使挑战是最终的
或者
. 在执行过程中,它实际上可以返回任何这些方法尚未触及的对象。 例如,采用这种方法在模板上 singleton:
让我们看看多次尝试创建对象类型时会发生什么
</class></class></class>
詹大官人
赞同来自:
当我将Metaclass视为我的问题的解决方案时,就是这样的情况:
我有一个真正复杂的问题,可能会有不同的解决,但我决定用一位测量来解决它。 由于困难,这是我在模块中的评论优于书面代码的范围的少数模块之一。 这里是...
</path>
江南孤鹜
赞同来自:
功能
返回对象的类型。
班级是他的
metaclass.
.
使用metaclass:
- 这是他自己的metaclass。 班级是一个metaclass; 该类的主体是由Metaclass传输的参数,用于构建类。
https://docs.python.org/3/refe ... asses
您可以阅读如何使用Metaclasses配置类。
小明明
赞同来自:
实际上是
-Class创建其他类。
最多
是亚距
.
获取类
作为其第一个参数,并提供对类对象的访问,详细信息如下所示:
请注意,此类未随时创建; 创建阶级的简单行为造成的执行
.
</class></class>
八刀丁二
赞同来自:
默认的元类,在确定类时使用:
元类用于将某些规则应用于整个类。 例如,假设您创建 ORM 要访问数据库并希望每个表中的记录属于与此表关联的类。 /基于字段,业务规则等/, 例如,可以使用MetAclarse是复合池的逻辑,这对于来自所有表的所有类别是共同的。 支持外部键的另一个使用逻辑,其中包括几个记录类。
定义Metaclass时,您输入子类的类型,您可以覆盖以下Magic方法以插入您的逻辑。
在任何情况下,最常使用这两个钩子。 MetaClass是一个强大的工具,高于GearsClasses的完整应用程序。
</bound></function>
江南孤鹜
赞同来自:
例如,我们可以创建一个类 Hi 使用功能 type// 并不使用此方法使用此方法 Hi/object/:
除了使用 type// 要动态创建类,可以控制创建类并使用Metaclass的行为。
根据对象模型 Python, 该类是对象,因此类必须是另一个特定类的实例。
默认类 Python 这是一个类实例 type. 也就是说,该类型是大多数嵌入类的Metaclass和用户类的Metaclass。
当我们在Metaclass中提供关键参数时,魔术将生效,表示翻译 Python 创建 CustomList 穿过 ListMetaclass.
new
//, 此时,我们可以更改类的定义,例如,添加新方法,然后返回修订后的定义。
石油百科
赞同来自:
确定类的行为。 因此,您可以明确安装Metaclass。 每当 Python 获取关键字
, 他开始看
. 如果找不到 – 要创建类对象,使用默认的元类类型。 使用属性
, 你可以设置
你的班:
他将产生这样的结果:
当然,你可以创建自己的
, 确定使用类创建的任何类的行为。
为此,您的类类型
默认应该是继承的,因为这是主要类
:
输出将是这样的:
卫东
赞同来自:
术语Metaclass只是意味着用于创建类的东西。 换句话说,这个类是课程。 MetaClass用于以与对象是类实例相同的方式创建类,该类是Metaclass的实例。 在 python 类也被认为是对象。
窦买办
赞同来自:
您可以使用
更改其实例的函数 /班级/.
是强大的,有很多东西 /比如猴子魔法/, 你可以用它做什么,但要小心,它只能知道你。
小明明
赞同来自:
, 替换使用MetaClasses的许多常见选项。 当创建子类以确定类时,将调用这一点。 看
https://docs.python.org/3.6/re ... .html
.
龙天
赞同来自:
创建MetaClass通常重新定义方法
new
// 和
init
//.
新的
// 您可以覆盖以更改方法,创建的对象
初始化
// 您可以覆盖以更改对象初始化方法。 可以通过多种方式创建元类。 一种方法 - 使用该功能 type//. 功能 type// 在打电话时 3 参数创建元类。 参数是这样的 :-
班级名称
一个具有由类继承的基本类的元组
包含所有类方法和类变量的字典
创建元壳的另一种方法包括一个关键字 'metaclass'. 确定Metaclass作为一个简单的类。 在继承类的参数中,通过 metaclass=metaclass_name
可以在下列情况下具体使用Metaclass。 :-
当某种效果应该适用于所有子类时
需要自动班级班次 /在创造时/
By API 开发人员
小明明
赞同来自:
画面质量:
Metaclass是一个类,其实例是类。 像课堂一样 "ordinary" 确定类实例的行为,Metaclass确定类的行为及其实例。
所有面向对象的编程语言都支持元峰。 这些编程语言在其实施方法中,支持元划分的语言显着不同。 Python 支持他们。
一些程序员看到了MetaClasses Python 作为 "solutions, 等候或寻求者 problem".
使用MetaClasses有许多选项。
Methaclasses的定义
:
它将打印其参数的内容
诺多诺姆
方法并返回类型的结果。
新的挑战
:
我们将使用Metaclass "LittleMeta" 在以下示例中:
出口
:
</class>
詹大官人
赞同来自:
在Python,这个类类,它决定了类的行为方式。 班级本身就是一个例子
. B级。 Python 确定类的实例如何表现。 我们可以通过传递关键字来配置类创建过程
在课堂的定义中。 它也可以通过继承类完成,该类已经过了此关键字。
我们可以看到课程类型
-这是
, 一种
和
-这是
.
确定课堂和缺席时
将使用默认类型。
. 如果设置值
这不是一个例子
, 然后它直接用于
.
可以特别地应用MetaClasses,以在创建和分析期间登录寄存器类。 他们似乎是完全抽象的概念,你可以想知道他们是否需要使用。
</class></class></class>
莫问
赞同来自: