Tri*_*ire 8 python metaclass python-3.x
我粗略地了解了什么是元类.它们是类对象所基于的类(因为类是Python中的对象).但有人可以解释(使用代码)如何创建一个.
(在这一点上)元类中有两个关键方法:
__prepare__,和__new____prepare__允许您提供OrderedDict在创建类时用作命名空间的自定义映射(例如).您必须返回您选择的任何名称空间的实例.如果没有实现__prepare__正常dict使用.
__new__ 负责最终课程的实际创作/修改.
一个简单的,无所事事的额外元类看起来像:
class Meta(type):
def __prepare__(metaclass, cls, bases):
return dict()
def __new__(metacls, cls, bases, clsdict):
return super().__new__(metacls, cls, bases, clsdict)
Run Code Online (Sandbox Code Playgroud)
一个简单的例子:
假设您需要一些简单的验证代码来运行您的属性 - 就像它必须始终是一个int或一个str.没有元类,你的类看起来像:
class Person:
weight = ValidateType('weight', int)
age = ValidateType('age', int)
name = ValidateType('name', str)
Run Code Online (Sandbox Code Playgroud)
如您所见,您必须重复两次属性的名称.这使得拼写错误以及恼人的错误成为可能.
一个简单的元类可以解决这个问题:
class Person(metaclass=Validator):
weight = ValidateType(int)
age = ValidateType(int)
name = ValidateType(str)
Run Code Online (Sandbox Code Playgroud)
这就是元类的样子(不使用,__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)
Run Code Online (Sandbox Code Playgroud)
示例运行:
p = Person()
p.weight = 9
print(p.weight)
p.weight = '9'
Run Code Online (Sandbox Code Playgroud)
生产:
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')
Run Code Online (Sandbox Code Playgroud)
笔记
这个例子很简单,它也可以用类装饰器完成,但可能是一个实际的元类会做得更多.
在Python 2.x中,该__prepare__方法不存在,并且该类通过包含类变量来规定其元类__metaclass__ = ...,如下所示:
class Person(object):
__metaclass__ = ValidateType
Run Code Online (Sandbox Code Playgroud)
'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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1038 次 |
| 最近记录: |