class Quantity:
__counter = 0
def __init__(self):
cls = self.__class__
self.storage = '_{}#{}'.format(cls.__name__, cls.__counter)
def __get__(self, instance, owner):
return instance.__dict__[self.storage]
def __set__(self, instance, value):
if value > 0:
instance.__dict__[self.storage] = value
else:
raise ValueError('value must be > 0')
# Quantity 类是可以自动生成 storage 名称的描述符类,和之前的逻辑基本类似,可以不用关注
# 继承自 type 类,是一个自定义的元类
class QuantityMeta(type):
def __init__(self, name, bases, attr_dict):
# name 表示类名,bases 是继承关系,attr_dict 则是属性列表,和 type 方法的参数含义一致
super().__init__(name, bases, attr_dict)
for key, attr in attr_dict.items():
# 注意,类有很多属性,但只有描述符类型的属性才需要修改
if isinstance(attr, Quantity):
type_name = type(attr).__name__
# 这里的 key 就是原来的属性名,比如 price、number
attr.storage = '_{}#{}'.format(type_name, key)
# 为了避免让用户知道太多元类的细节,我们创建一个基类 Entity,并把它的元类设置为 QuantityMeta
class Entity(metaclass=QuantityMeta): pass
# 现在用户的类只要继承自 Entity 就可以了
class Item(Entity):
price = Quantity()
number = Quantity()
def __init__(self):
pass
i = Item()
i.price = 1
print(i.__dict__) # 得到 {'_Quantity#price': 1},可读性良好
#i.price = -1 # 抛出异常