什么是甲状腺?它们用于什么?
当前回答
请注意,在Python 3.6中,引入了一个新的Dunder方法 __init_subclass__(cls, **kwargs),以取代许多常见的使用案例为MetaClass。
其他回答
当班级声明执行时,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__
此分類上一篇: tl;dr version
类型(obj)函数会给你一个对象的类型。
一个阶级的类型( )是它的甲型阶级。
使用甲状腺:
class Foo(object):
__metaclass__ = MyMetaClass
一个类的类是一个类的类 - 一个类的身体是转移到一个类的论点,它被用来构建一个类。
在这里,你可以阅读如何使用金属玻璃来自定义课堂建筑。
除了发布的答案,我可以说,一个甲状腺可以定义一个类的行为,所以,你可以明确设置你的甲状腺,每当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'
>>> class ObjectCreator(object):
... pass
>>> my_object = ObjectCreator()
>>> print(my_object)
<__main__.ObjectCreator object at 0x8974f2c>
>>> class ObjectCreator(object):
... pass
>>> print(JustAnotherVariable)
<class '__main__.ObjectCreator'>
>>> print(JustAnotherVariable())
<__main__.ObjectCreator object at 0x8997b4c>
>>> 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>
>>> print(type(1))
<type 'int'>
>>> print(type("1"))
<type 'str'>
>>> print(type(ObjectCreator))
<type 'type'>
>>> print(type(ObjectCreator()))
<class '__main__.ObjectCreator'>
type(name, bases, attrs)
>>> 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>
>>> class Foo(object):
... bar = True
>>> Foo = type('Foo', (), {'bar':True})
>>> print(Foo)
<class '__main__.Foo'>
>>> print(Foo.bar)
True
>>> f = Foo()
>>> print(f)
<__main__.Foo object at 0x8a9b84c>
>>> print(f.bar)
True
>>> class FooChild(Foo):
... pass
>>> FooChild = type('FooChild', (Foo,), {})
>>> print(FooChild)
<class '__main__.FooChild'>
>>> print(FooChild.bar) # bar is inherited from Foo
True
>>> def echo_bar(self):
... print(self.bar)
...
>>> FooChild = type('FooChild', (Foo,), {'echo_bar': echo_bar})
>>> hasattr(Foo, 'echo_bar')
False
>>> hasattr(FooChild, 'echo_bar')
True
>>> my_foo = FooChild()
>>> my_foo.echo_bar()
True
>>> def echo_bar_more(self):
... print('yet another method')
...
>>> FooChild.echo_bar_more = echo_bar_more
>>> hasattr(FooChild, 'echo_bar_more')
True
MyClass = MetaClass()
my_object = MyClass()
MyClass = type('MyClass', (), {})
>>> age = 35
>>> age.__class__
<type 'int'>
>>> name = 'bob'
>>> name.__class__
<type 'str'>
>>> def foo(): pass
>>> foo.__class__
<type 'function'>
>>> class Bar(object): pass
>>> b = Bar()
>>> b.__class__
<class '__main__.Bar'>
>>> age.__class__.__class__
<type 'type'>
>>> name.__class__.__class__
<type 'type'>
>>> foo.__class__.__class__
<type 'type'>
>>> b.__class__.__class__
<type 'type'>
class Foo(object):
__metaclass__ = something...
[...]
class Foo(Bar):
pass
设置 meta 类的合成已在 Python 3 中更改:
class Foo(object, metaclass=something):
...
class Foo(object, metaclass=something, kwarg1=value1, kwarg2=value2):
...
# 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'
>>> hasattr(Foo, 'bar')
False
>>> hasattr(Foo, 'BAR')
True
>>> Foo.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)
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)
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()
}
# Python 2 requires passing arguments to super:
return super(UpperAttrMetaclass, cls).__new__(
cls, clsname, bases, uppercase_attrs)
# Python 3 can use no-arg super() which infers them:
return super().__new__(cls, clsname, bases, uppercase_attrs)
class Foo(object, metaclass=MyMetaclass, kwarg1=value1):
...
class MyMetaclass(type):
def __new__(cls, clsname, bases, dct, kwargs1=default):
...
使用金属玻璃代码的复杂性背后的原因不是由于金属玻璃,而是因为你通常使用金属玻璃来制作依赖于入观、操纵遗产、如 __dict__ 等的旋转物品。
有几个理由这样做:
為什麼要使用MetaClass?
现在,大问题:为什么你会使用一些模糊的错误漏洞功能?
如果你想知道你是否需要它们,你不会(真正需要它们的人肯定知道他们需要它们,不需要解释为什么)。
Python Guru 蒂姆·彼得斯
class Person(models.Model):
name = models.CharField(max_length=30)
age = models.IntegerField()
person = Person(name='bob', age='35')
print(person.age)
最后一句话
首先,你知道,类是可以创造例子的物体。
>>> class Foo(object): pass
>>> id(Foo)
142630324
99%的时间你需要课堂变化,你更好地使用这些。
但98%的时间,你根本不需要课堂变化。
下面是另一个例子,它可以用于什么:
您可以使用甲状腺来改变其例子(类)的功能。
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()
金星是强大的,有很多事情(如猴子魔法)你可以用它,但要小心,这可能只是你知道的。
推荐文章
- Python glob多个文件类型
- 如何可靠地打开与当前运行脚本在同一目录下的文件
- Python csv字符串到数组
- 如何将类标记为已弃用?
- 如何在Python中进行热编码?
- 如何嵌入HTML到IPython输出?
- 在Python生成器上使用“send”函数的目的是什么?
- 是否可以将已编译的.pyc文件反编译为.py文件?
- Django模型表单对象的自动创建日期
- 在Python中包装长行
- 如何计算两个时间串之间的时间间隔
- 我如何才能找到一个Python函数的参数的数量?
- getter和setter是糟糕的设计吗?相互矛盾的建议
- 您可以使用生成器函数来做什么?
- 将Python诗歌与Docker集成