python自定义元类,约束子类
"""
对象的类型称为类,类的类就称为元类。Python 中对元类实例化的结果就是“普通类”,这个过程是动态的。
在定义类时可以指定元类来改变类的创建过程。
你想创建某一批类全部必须实现某种方法属性,则可通过 metaclass = ModelBase 来实现。
若在继承了type的类如:ModelBase(type),并重写 new() 方法,使用 metaclass 可以在创建类时动态修改类定义。
new(cls,) 用来创建一个(未初始化)实例;init(self,) 则是用来初始化一个实例。
在定义metaclass = ModelBase元类的 new 方法中,因为类实例还没有创建,所以可以更改最后生成类的各项属性:诸如名称,基类或属性,方法等。
而在 init 中由于类已经创建完成,所以无法改变。
"""
class ModelBase(type):
"""
cls 代表动态修改的类
name 字符串类型,存放新类的名字
bases 元组(tuple)类型,指定类的基类/父类
attrs 字典类型,存放该类的所有属性(attributes)和方法(method)
"""
def __new__(cls, name, bases, attrs, ):
super_new = super().__new__
# 还确保初始化只对模型子类执行(不包括模型类本身)
parents = [b for b in bases if isinstance(b, ModelBase)]
if not parents:
# 创建子类,动态添加方法
attrs['totalpay'] = lambda self: self.price * self._discount if self.price and self._discount else None
return super_new(cls, name, bases, attrs)
class storeModel(metaclass=ModelBase):
__slots__ = ('name', 'price', '_discount')
def __init__(self, name, price):
self.name = name
self.price = price
@property
def discount(self):
return self._discount
@discount.setter
def discount(self, discount):
self._discount = discount
@property
def run(self):
print("七夕节给女朋友买{}一共花费{}···".format(self.name, self.totalpay()))
# 实例化
obj = storeModel('苹果', 1000)
obj.discount = 0.1
obj.run
obj = storeModel('香蕉', 100000)
obj.discount = 0.1
obj.run
# 内置函数反射方法,直接修改
setattr(storeModel, 'price', 2000)
obj.run