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


当前回答

我看到一个有趣的使用案例在一个名为类用途的包中,它检查是否所有类变量在顶部案例格式(方便有统一逻辑的配置类),并检查是否没有例子级方法在课堂上。

其他回答

其他人已经解释了金属玻璃是如何工作的,它们是如何适应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 的子类,然后获得一个类属性 _ 命令,记录了类被定义的顺序。

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 首先将班级声明的身体作为一个正常的代码块执行。 结果的名称空间(dict)保留了班级的属性. 金属阶级通过观察班级的基层(金属阶级继承),在 __金属阶级__属性的班级(如果有)或 __金属阶级__全球变量来确定。

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__

上面的答案是正确的。

但读者可能来到这里寻找关于类似名称的内部课程的答案,他们在受欢迎的图书馆,如Django和WTForms。

相反,这些是班级的命令之内的名称空间,它们是用内部班级为可读性而建造的。

在这个特殊的例子领域,抽象是显而易见地与作者模型的领域分开。

from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=50)
    email = models.EmailField()

    class Meta:
        abstract = True

另一个例子是WTForms的文档:

from wtforms.form import Form
from wtforms.csrf.session import SessionCSRF
from wtforms.fields import StringField

class MyBaseForm(Form):
    class Meta:
        csrf = True
        csrf_class = SessionCSRF

    name = StringField("name")

这个合成不会在Python编程语言中得到特别的处理. Meta 不是这里的一个关键词,也不会引发 meta 类行为. 相反,第三方图书馆代码在 Django 和 WTForms 等包中,在某些类的构建者和其他地方读到这个属性。

这些声明的存在改变了具有这些声明的类别的行为. 例如,WTForms 阅读 self.Meta.csrf 以确定表格是否需要一个 csrf 字段。

什么是Metaclasses?你用它们用于什么?

>>> Class(...)
instance

>>> Metaclass(...)
Class

>>> type('Foo', (object,), {}) # requires a name, bases, and a namespace
<class '__main__.Foo'>

每当你创建一个类时,你都会使用一个类型:

class Foo(object): 
    'demo'

>>> Foo
<class '__main__.Foo'>
>>> isinstance(Foo, type), isinstance(Foo, object)
(True, True)

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

>>> Foo.__dict__
dict_proxy({'__dict__': <attribute '__dict__' of 'Foo' objects>, 
'__module__': '__main__', '__weakref__': <attribute '__weakref__' 
of 'Foo' objects>, '__doc__': 'demo'})

(在 __dict__: __module__ 类的内容上有一个侧笔记,因为类必须知道它们在哪里定义,而 __dict__ 和 __weakref__ 是因为我们不定义 __slots__ - 如果我们定义 __slots__ 我们会在例子中节省一些空间,因为我们可以通过排除它们来排除 __dict__ 和 __weakref__。

>>> Baz = type('Bar', (object,), {'__doc__': 'demo', '__slots__': ()})
>>> Baz.__dict__
mappingproxy({'__doc__': 'demo', '__slots__': (), '__module__': '__main__'})

我们可以像任何其他类定义一样扩展类型:

>>> Foo
<class '__main__.Foo'>

class Type(type):
    def __repr__(cls):
        """
        >>> Baz
        Type('Baz', (Foo, Bar,), {'__module__': '__main__', '__doc__': None})
        >>> 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):
        """
        >>> Baz == eval(repr(Baz))
        True            
        """
        return (cls.__name__, cls.__bases__, cls.__dict__) == (
                other.__name__, other.__bases__, other.__dict__)

>>> class Bar(object): pass
>>> Baz = Type('Baz', (Foo, Bar,), {'__module__': '__main__', '__doc__': None})
>>> Baz
Type('Baz', (Foo, Bar,), {'__module__': '__main__', '__doc__': None})

但是,与 eval(repr(Class))的进一步检查是不可能的(因为函数将是相当不可能从他们的默认 __repr__ 的 eval 。

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

>>> OrderedMethodsObject.members
('__module__', '__qualname__', 'method1', 'method2', 'method3', 'method4')

>>> inspect.getmro(OrderedType)
(<class '__main__.OrderedType'>, <class '__main__.Type'>, <class 'type'>, <class 'object'>)

而且它大约有正确的回报(除非我们能找到代表我们的功能的方式,否则我们就不能再评估):

>>> OrderedMethodsObject
OrderedType('OrderedMethodsObject', (object,), {'method1': <function OrderedMethodsObject.method1 at 0x0000000002DB01E0>, 'members': ('__module__', '__qualname__', 'method1', 'method2', 'method3', 'method4'), 'method3': <function OrderedMet
hodsObject.method3 at 0x0000000002DB02F0>, 'method2': <function OrderedMethodsObject.method2 at 0x0000000002DB0268>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'OrderedMethodsObject' objects>, '__doc__': None, '__d
ict__': <attribute '__dict__' of 'OrderedMethodsObject' objects>, 'method4': <function OrderedMethodsObject.method4 at 0x0000000002DB0378>})