class type(object)
| type(object) -> the object's type
| type(name, bases, dict) -> a new type
元类需要3个参数名称'、'基'和'字典'
秘密就从这里开始。在这个示例类定义中查找名称、基和dict的来源。
class ThisIsTheName(Bases, Are, Here):
All_the_code_here
def doesIs(create, a):
dict
让我们定义一个元类来演示“类:”如何调用它。
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'
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
>>> class ObjectCreator(object):
... pass
...
>>> my_object = ObjectCreator()
>>> print(my_object)
<__main__.ObjectCreator object at 0x8974f2c>
但在Python中,类不仅仅是这样。类也是对象。
是的,物体。
只要使用关键字class,Python就会执行它并创建
一个物体。指示
>>> 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>
type(name of the class,
tuple of the parent class (for inheritance, can be empty),
dictionary containing attributes names and values)
例如:
>>> class MyShinyClass(object):
... pass
可以通过以下方式手动创建:
>>> 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>
# 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_attr):
"""
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_attr = {}
for name, val in future_class_attr.items():
if not name.startswith('__'):
uppercase_attr[name.upper()] = val
else:
uppercase_attr[name] = val
# let `type` do the class creation
return type(future_class_name, future_class_parents, uppercase_attr)
__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'
print(hasattr(Foo, 'bar'))
# Out: False
print(hasattr(Foo, 'BAR'))
# Out: True
f = Foo()
print(f.BAR)
# Out: '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_attr):
uppercase_attr = {}
for name, val in future_class_attr.items():
if not name.startswith('__'):
uppercase_attr[name.upper()] = val
else:
uppercase_attr[name] = val
return type(future_class_name, future_class_parents, uppercase_attr)
但这并不是很糟糕。我们直接调用type而不重写
或者调用父级__new__。我们来做吧:
class UpperAttrMetaclass(type):
def __new__(upperattr_metaclass, future_class_name,
future_class_parents, future_class_attr):
uppercase_attr = {}
for name, val in future_class_attr.items():
if not name.startswith('__'):
uppercase_attr[name.upper()] = val
else:
uppercase_attr[name] = val
# reuse the type.__new__ method
# this is basic OOP, nothing magic in there
return type.__new__(upperattr_metaclass, future_class_name,
future_class_parents, uppercase_attr)
class UpperAttrMetaclass(type):
def __new__(cls, clsname, bases, dct):
uppercase_attr = {}
for name, val in dct.items():
if not name.startswith('__'):
uppercase_attr[name.upper()] = val
else:
uppercase_attr[name] = val
return type.__new__(cls, clsname, bases, uppercase_attr)
我们可以通过使用super使其更干净,这将简化继承(因为可以有元类,从元类继承,从类型继承):
class UpperAttrMetaclass(type):
def __new__(cls, clsname, bases, dct):
uppercase_attr = {}
for name, val in dct.items():
if not name.startswith('__'):
uppercase_attr[name.upper()] = val
else:
uppercase_attr[name] = val
return super(UpperAttrMetaclass, cls).__new__(cls, clsname, bases, uppercase_attr)
哦,在python 3中,如果使用关键字参数执行此调用,如下所示:
class Foo(object, metaclass=Thing, kwarg1=value1):
...
它在元类中转换成这个来使用它:
class Thing(type):
def __new__(cls, clsname, bases, dct, kwargs1=default):
...
Metaclasses are deeper magic that
99% of users should never 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).
Python大师蒂姆·彼得斯
元类的主要用例是创建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)
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年编写的,3.x中的元类略有不同。
元类是使“类”起作用的秘密调味料。新样式对象的默认元类称为“type”。
元类需要3个参数名称'、'基'和'字典'
秘密就从这里开始。在这个示例类定义中查找名称、基和dict的来源。
让我们定义一个元类来演示“类:”如何调用它。
现在,一个实际意义重大的例子,它会自动将列表“attributes”中的变量设置在类上,并设置为None。
注意,
Initialised
通过拥有元类而获得的神奇行为init_attributes
不会传递给Initialised
的子类。下面是一个更具体的例子,展示了如何将“type”子类化,以生成在创建类时执行操作的元类。这很棘手:
类作为对象
在理解元类之前,您需要掌握Python中的类。Python从Smalltalk语言中借鉴了一个非常独特的概念,即类是什么。
在大多数语言中,类只是描述如何生成对象的代码片段。在Python中也是这样:
但在Python中,类不仅仅是这样。类也是对象。
是的,物体。
只要使用关键字
class
,Python就会执行它并创建 一个物体。指示在内存中创建名为“ObjectCreator”的对象。
这个对象(类)本身能够创建对象(实例), 这就是为什么它是一个类。
但它仍然是一个物体,因此:
例如:
动态创建类
因为类是对象,所以可以像任何对象一样动态创建它们。
首先,可以使用
class
在函数中创建类:但它不是那么有活力,因为你还得自己写全班。
因为类是对象,所以它们必须由某种东西生成。
使用
class
关键字时,Python会自动创建此对象。但是作为 对于Python中的大多数内容,它提供了一种手动执行的方法。还记得功能吗?让你知道 对象类型为:
嗯,^{} 具有完全不同的能力,它还可以动态创建类。
type
可以将类的描述作为参数, 然后还一个班。(我知道,同一个函数根据传递给它的参数可以有两个完全不同的用途,这很愚蠢。这是一个向后的问题 Python中的兼容性)
type
这样工作:例如:
可以通过以下方式手动创建:
你会注意到我们使用“MyShinyClass”作为类的名称 作为保存类引用的变量。它们可以不同, 但没有理由把事情复杂化。
type
接受字典来定义类的属性。所以:可翻译为:
作为普通班使用:
当然,你可以继承它,所以:
将是:
最终,您将希望向类中添加方法。定义一个函数 使用正确的签名并将其指定为属性。
在动态创建类之后,您可以添加更多的方法,就像向通常创建的类对象添加方法一样。
您可以看到我们的目的:在Python中,类是对象,您可以动态地动态地创建一个类。
这就是Python在使用关键字
class
时所做的,它是通过使用元类来实现的。什么是元类(最后)
元类是创建类的“材料”。
你定义类是为了创建对象,对吧?
但是我们了解到Python类是对象。
好吧,元类是创建这些对象的工具。他们是班级的班级, 你可以这样想象:
你已经看到
type
让你做这样的事情:因为函数
type
实际上是一个元类。type
是 Python使用元类在幕后创建所有类。现在你想知道为什么它是用小写写的,而不是
Type
?好吧,我想这是一个与
str
一致的问题,这个类创建 字符串对象,以及int
创建整数对象的类.type
是 只是创建类对象的类。通过检查
__class__
属性可以看到这一点。一切,我是说一切,都是Python中的一个对象。包括整数, 字符串、函数和类。它们都是物体。他们都有 从类创建:
现在,任何
__class__
的__class__
是什么?所以,元类只是创建类对象的东西。
如果你愿意的话,可以称之为“一流工厂”。
type
是Python使用的内置元类,当然,您可以创建 自己的元类。^{} 属性
在Python 2中,编写类时可以添加
__metaclass__
属性(Python 3语法请参见下一节):如果这样做,Python将使用元类创建类
Foo
。小心,这很棘手。
你先写
class Foo(object)
,但是类对象Foo
没有创建 在记忆里。Python将在类定义中查找
__metaclass__
。如果它找到了, 它将使用它来创建对象类Foo
。如果没有,它将使用type
创建类。读几遍。
当你这样做时:
Python执行以下操作:
在
Foo
中是否有__metaclass__
属性?如果是,请在内存中创建一个名为
Foo
的类对象(我说的是一个类对象,请留在这里),方法是使用__metaclass__
中的内容。如果Python找不到
__metaclass__
,它将在模块级查找__metaclass__
,并尝试执行相同的操作(但仅限于不继承任何内容的类,基本上是旧式类)。如果它根本找不到任何
__metaclass__
,它将使用Bar
(第一个父类)自己的元类(可能是默认的type
)来创建类对象。请注意,这里的
__metaclass__
属性不会被继承,父类(Bar.__class__
)的元类将被继承。如果Bar
使用了一个__metaclass__
属性,该属性用type()
(而不是type.__new__()
)创建了Bar
,则子类将不会继承该行为。现在最大的问题是,你能在
__metaclass__
中放些什么?答案是:可以创建类的东西。
什么可以创建一个类?
type
,或任何子类或使用它的东西。Python 3中的元类
设置元类的语法在Python3中已更改:
也就是说,不再使用
__metaclass__
属性,而是使用基类列表中的关键字参数。但是,元类的行为仍然是largely the same。
python 3中添加到元类的一件事是,您还可以将属性作为关键字参数传递到元类中,如下所示:
阅读下面的一节了解python如何处理这个问题。
自定义元类
元类的主要目的是自动更改类, 当它被创造出来的时候。
您通常为api执行此操作,在api中创建与 当前上下文。
想象一个愚蠢的例子,在这个例子中,你决定在你的模块中的所有类 应该用大写字母书写它们的属性。有几种方法可以 这样做,但一种方法是在模块级设置
__metaclass__
。这样,这个模块的所有类都将使用这个元类创建, 我们只需要告诉元类将所有属性转换为大写。
幸运的是,
__metaclass__
实际上可以是任何可调用的,它不需要是 正式的类(我知道,名字中有“类”的东西不需要 一个班,想办法。。。但这很有帮助)。所以我们将从一个简单的例子开始,使用一个函数。
现在,让我们做同样的事情,但是对元类使用一个真正的类:
但这并不是很糟糕。我们直接调用
type
而不重写 或者调用父级__new__
。我们来做吧:您可能注意到了额外的参数
upperattr_metaclass
。有 没有什么特别之处:__new__
总是将它在中定义的类作为第一个参数接收。就像对于接收实例作为第一个参数的普通方法,或者类方法的定义类,都有self
。当然,为了清楚起见,我在这里使用的名字很长,但是 对于
self
,所有参数都有常规名称。所以一部真正的作品 元类如下所示:我们可以通过使用
super
使其更干净,这将简化继承(因为可以有元类,从元类继承,从类型继承):哦,在python 3中,如果使用关键字参数执行此调用,如下所示:
它在元类中转换成这个来使用它:
就这样。关于元类真的没有什么了。
使用元类的代码之所以复杂,并不是因为 关于元类,这是因为你通常使用元类来做扭曲的事情 依赖内省、操纵继承、变量如
__dict__
等确实,元类在执行黑魔法时特别有用,因此 复杂的东西。但就其本身而言,它们很简单:
为什么要使用元类类而不是函数?
既然
__metaclass__
可以接受任何可调用的,为什么要使用类 因为事情显然更复杂?这样做有几个原因:
UpperAttrMetaclass(type)
时,你知道 接下来会发生什么__new__
、__init__
和__call__
。这将允许 你要做不同的事。即使你通常都能在__new__
中完成, 有些人更喜欢使用__init__
。为什么要使用元类?
现在是个大问题。为什么你会使用一些模糊的易出错特性?
通常你不会:
Python大师蒂姆·彼得斯
元类的主要用例是创建API。典型的例子是Django ORM。
它允许您定义如下内容:
但如果你这样做:
它不会返回
IntegerField
对象。它将返回一个int
,甚至可以直接从数据库中获取它。这是可能的,因为
models.Model
定义了__metaclass__
和 它使用了一些魔法,可以将刚才用简单语句定义的Person
连接到数据库字段的复杂钩子。Django通过公开一个简单的API使复杂的事情看起来很简单 使用元类,从这个API重新创建代码来完成真正的工作 在幕后。
最后一句话
首先,您知道类是可以创建实例的对象。
实际上,类本身就是实例。元类的。
一切都是Python中的一个对象,它们都是类的实例 或者元类的实例。
除了
type
。type
实际上是它自己的元类。这不是你能做到的 在纯Python中复制,并通过欺骗一点点的实现 水平。其次,元类是复杂的。你可能不想用它们 非常简单的班级变动。您可以使用两种不同的技术来更改类:
99%的时候你需要修改课程,你最好用这些。
但98%的时候,你根本不需要改变班级。
元类是类的类。类定义类的实例(即对象)的行为,而元类定义类的行为。类是元类的实例。
在Python中,可以对元类使用任意的可调用项(如Jerub所示),更好的方法是使其成为实际的类本身。
type
是Python中常见的元类。type
本身就是一个类,它是自己的类型。纯用Python无法重新创建类似type
的内容,但Python有点作弊。要在Python中创建自己的元类,您只需要将type
子类化。元类最常用作类工厂。当通过调用类创建对象时,Python通过调用元类创建一个新类(当它执行“class”语句时)。因此,与普通的
__init__
和__new__
方法相结合,元类允许您在创建类时执行“额外的操作”,比如在某些注册表中注册新类,或者用其他完全替换类。当执行
class
语句时,Python首先将class
语句的主体作为普通代码块执行。结果命名空间(dict)保存类的属性。元类是通过查看要成为类的基类(元类是继承的)、要成为类的__metaclass__
属性(如果有的话)或__metaclass__
全局变量来确定的。然后使用类的名称、基和属性调用元类来实例化它。然而,元类实际上定义了类的类型,而不仅仅是类的工厂,因此您可以对它们做更多的工作。例如,可以在元类上定义普通方法。这些元类方法类似于类方法,因为它们可以在没有实例的类上调用,但它们也不同于类方法,因为它们不能在类的实例上调用。
type.__subclasses__()
是type
元类上的一个方法示例。您还可以定义普通的“magic”方法,例如__add__
、__iter__
和__getattr__
,以实现或更改类的行为方式。下面是位和块的聚合示例:
相关问题 更多 >
编程相关推荐