python类创建过程

类创建过程
#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__方法
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值