视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
详细讲解Python中的元类及其用法
2020-11-27 14:23:32 责编:小采
文档


1、用元类验证子类

每当我们定义新类的时候,元类就会运行雅正代码,以确保这个新类符合规定的规范。
Python系统把子类的class语句处理完毕,就会调用元类的 __new__ 方法。元类可以通过 __new__ 方法,获取子类、孙子类的名称,父亲及属性。
这样使得我们不需要将验证代码放在本类 __init__ 方法中,等到构建对象再验证。

下例中,定义一个边数小于3的子类,class语句一结束,元类的验证代码就会拒绝这个class。

class ValidatePolygon(type):
 def __new__(meta, name, bases, class_dict):
 # Don't validate the abstract Polygon class
 if bases != (object,):
 if class_dict['sides'] < 3:
 raise ValueError('Polygons need 3+ sides')
 return type.__new__(meta, name, bases, class_dict)

class Polygon(object, metaclass=ValidatePolygon):
 sides = None # Specified by subclasses

 @classmethod
 def interior_angles(cls):
 return (cls.sides - 2) * 180

class Triangle(Polygon):
 sides = 3

print(Triangle.interior_angles())

2、用元类注册子类

每次从基类中继承子类时,基类的元类都可以自动运行注册代码。
这在需要反向查找 ‘reverse lookup’ 时很有用,使得在简单标识符和对应的类之间,建立映射关系。
依然利用的是class语句执行完,自动调用元类的 __new__ 方法。

import json 

registry = {}

def register_class(target_class):
 registry[target_class.__name__] = target_class

def deserialize(data):
 params = json.loads(data)
 name = params['class']
 target_class = registry[name]
 return target_class(*params['args'])


class Meta(type):
 def __new__(meta, name, bases, class_dict):
 cls = type.__new__(meta, name, bases, class_dict)
 register_class(cls)
 return cls


class Serializable(object):
 def __init__(self, *args):
 self.args = args

 def serialize(self):
 return json.dumps({
 'class': self.__class__.__name__,
 'args': self.args,
 })

 def __repr__(self):
 return '%s(%s)' % (
 self.__class__.__name__,
 ', '.join(str(x) for x in self.args))


class RegisteredSerializable(Serializable, metaclass=Meta):
 pass


class Vector3D(RegisteredSerializable):
 def __init__(self, x, y, z):
 super().__init__(x, y, z)
 self.x, self.y, self.z = x, y, z


v3 = Vector3D(10, -7, 3)
print('Before: ', v3)
data = v3.serialize()
print('Serialized:', data)
print('After: ', deserialize(data))

print(registry)

3、用元类注解类的属性

使用元类像是在 class 语句上放置了挂钩,class语句处理完毕,挂钩就会立刻触发。
下列中借助元类设置了 Filed.nameFiled.name

class Field(object):
 def __init__(self):
 # These will be assigned by the metaclass.
 self.name = None
 self.internal_name = None
 
 def __get__(self, instance, instance_type):
 if instance is None: return self
 return getattr(instance, self.internal_name, '')

 def __set__(self, instance, value):
 setattr(instance, self.internal_name, value)


class Meta(type):
 def __new__(meta, name, bases, class_dict):
 for key, value in class_dict.items():
 if isinstance(value, Field):
 value.name = key
 value.internal_name = '_' + key
 cls = type.__new__(meta, name, bases, class_dict)
 return cls


class DatabaseRow(object, metaclass=Meta):
 pass


class BetterCustomer(DatabaseRow):
 first_name = Field()
 last_name = Field()
 prefix = Field()
 suffix = Field()


foo = BetterCustomer()
print('Before:', repr(foo.first_name), foo.__dict__)
foo.first_name = 'Euler'
print('After: ', repr(foo.first_name), foo.__dict__)

元类总结就到这里,自己也没有完全理解清楚。
希望对此有深刻理解的pythoner留言。

代码来自:

下载本文
显示全文
专题