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  阅读(356)  评论(0编辑  收藏  举报