类创建过程
#coding=utf8
import abc
import collections
class AutoStorage:
"""描述符"""
__counter = 0
def __init__(self):
cls = self.__class__
prefix = cls.__name__
index = cls.__counter
self.storage_name = '_{}#{}'.format(prefix, index)
cls.__counter += 1
def __get__(self, instance, owner):
if instance is None:
return self
else:
return getattr(instance, self.storage_name)
def __set__(self, instance, value):
setattr(instance, self.storage_name, value)
class Validated(abc.ABC, AutoStorage):
"""描述符子类,增加抽象方法validate用于验证数据有效性"""
def __set__(self, instance, value):
value = self.validate(instance, value)
super().__set__(instance, value)
@abc.abstractmethod
def validate(self, instance, value):
"""return validated value or raise ValueError"""
class Quantity(Validated):
"""用于验证的实现类
a number greater than zero"""
def validate(self, instance, value):
if value <= 0:
raise ValueError('value must be > 0')
return value
class NonBlank(Validated):
"""用于验证的实现类
a string with at least one non-space character"""
def validate(self, instance, value):
value = value.strip()
if len(value) == 0:
raise ValueError('value cannot be empty or blank')
return value
class EntityMeta(type):
"""元类,用于创建类
Metaclass for business entities with validated fields"""
@classmethod
def __prepare__(cls, name, bases):
"""<1>python3.4新增方法,在所有类定义开始执行前首先被调用,用来创建类命名空间。
这里通过返回了一个OrderedDict而不是一个普通的字典,可以很容易的捕获定义的顺序。"""
return collections.OrderedDict()
def __new__(cls, name, bases, attr_dict):
"""<2>用来实例化最终的类对象。
cls为EntityMeta,name为LineItem,此方法创建LineItem类对象并传递给__init__方法初始化"""
d = dict(attr_dict)
order = []
for name, value in attr_dict.items():
order.append(name)
d['_order'] = order
return type.__new__(cls, name, bases, d)
def __init__(cls, name, bases, attr_dict):
"""<3>最后被调用,用来执行其他的一些初始化工作。
cls为类对象LineItem,此处应该为self,用cls是为了表示要构建的实例是类,
name为LineItem,接收__new__方法创建的类对象,初始化类属性"""
super().__init__(name, bases, attr_dict)
cls._field_names = [] # <2>
for key, attr in attr_dict.items():
if isinstance(attr, Validated):
type_name = type(attr).__name__
attr.storage_name = '_{}#{}'.format(type_name, key) # 设置描述符实例对象属性名称
cls._field_names.append(key)
def __call__(self, *args, **kwargs):
"""<4>创建子类实例时调用,会调用子类__init__方法初始化对像"""
super().__call__(*args, **kwargs)
class Entity(metaclass=EntityMeta):
"""Business entity with validated fields"""
@classmethod
def field_names(cls):
for name in cls._field_names:
yield name
class LineItem(model.Entity):
description = model.NonBlank() # 描述符对象,检查值不能为空
weight = model.Quantity() # 描述符对象,检查值不能小于等于0
price = model.Quantity() # 描述符对象,检查值不能小于等于0
def __init__(self, description, weight, price):
"""<5>类为可调用对象,由元类的__call__调用"""
self.description = description # 调用描述符对象的__set__方法
self.weight = weight # 调用描述符对象的__set__方法
self.price = price # 调用描述符对象的__set__方法
def subtotal(self):
return self.weight * self.price
if __name__ == '__main__'
raisins = LineItem('Golden raisins', 10, 6.95)
print(raisins.weight, raisins.description, raisins.price) # 调用描述述对象的__get__方法