python自定义元类metaclass,约束子类

对象的类型称为类,类的类就称为元类。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

posted @ 2020-08-25 21:21  justblue  阅读(405)  评论(0)    收藏  举报