什么是甲状腺?它们用于什么?


当前回答

Python 3 更新

在一个甲状腺中,有(目前)两个关键方法:

__prepare__ 允许您提供自定义地图(如 OrderedDict)作为名称空间使用,而类正在创建。

__new__ 负责最终类的实际创建/修改。

一个色彩色彩,不做任何东西 - 额外的金属类会喜欢:

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. 没有一个 metaclass,你的类会看起来像:

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

正如你可以看到的那样,你必须重复属性的名称两次,这使得类型与刺激的错误一起可能。

一个简单的甲状腺可以解决这个问题:

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

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')

注意:这个例子是简单的,它也可能已经完成了一个类装饰师,但假设一个真正的金属玻璃会做得更多。

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

其他回答

除了发布的答案,我可以说,一个甲状腺可以定义一个类的行为,所以,你可以明确设置你的甲状腺,每当Python获得一个关键词类,然后它开始搜索甲状腺,如果它没有找到 - 默认甲状腺类型用于创建一个类的对象,使用 __metaclass__属性,你可以设置你的甲状腺类:

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

print(MyClass.__metaclass__)

它将产生这样的产量:

class 'type'

当然,你可以创建自己的金属类来定义使用你的类创建的任何类的行为。

要做到这一点,您的默认金属类型类必须继承,因为这是主要金属类:

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'

在Python中,一类是指一个子类的子类,它决定一个子类的行为方式;在Python中,一类是另一个子类的例子;在Python中,一类是指一个子类的例子将如何行事。

由于甲基层负责类型,所以你可以写自己的自定义甲基层来改变类型是通过执行额外的操作或注射代码创建的方式。

Metaclasses 是做“类”的工作的秘密酱油,新风格对象的默认 metaclass 被称为“类型”。

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

Metaclasses 取 3 args. 'name', 'bases' 和 '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'

现在,一个实际上意味着什么的例子,这将自动使列表中的变量“属性”设置在课堂上,并设置为无。

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 =>', Initialised.foo
# output=>
foo => None

请注意,启动者获得的魔法行为是通过拥有金属类的 init_属性而没有转移到启动者的子类。

这里是一个更具体的例子,显示如何可以创建一个在创建一个类时执行一个行动的甲型类的“类型”。

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

Python 类本身是它们的 meta 类的对象 - 例如。

默认的金属类,当您确定类时应用于:

class foo:
    ...

例如,假设您正在构建一个ORM访问数据库,并且您希望每个表中的记录来自一个类地图到该表(基于字段,业务规则等),一个可能的使用MetaClass是例如,连接池逻辑,由所有表中的记录的所有类共享。

当你定义甲型时,你可以分类类型,并且可以超越下列魔法方法来插入你的逻辑。

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__ ->  type.__new__ -> type.__init__ -> 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

无论如何,这两种是最常用的<unk>子,甲板是强大的,上面没有附近和完整的用途列表用于甲板。

其他人已经解释了金属玻璃是如何工作的,它们是如何适应Python类型系统的,这里有一个例子,它们可以用于什么。在我写的测试框架中,我想跟踪在哪个类被定义的顺序,以便我后来能够在这个顺序中安装它们,我发现使用金属玻璃最容易做到这一点。

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 的子类,然后获得一个类属性 _ 命令,记录了类被定义的顺序。