Effective Python 读书笔记: 第35条: 用元类来注解类的属性

# -*- encoding: utf-8 -*-

import os

'''
第35条: 用元类来注解类的属性

关键:
1 元类
作用:在类定义好但是还没有使用的时候,提前修改或注解类的属性,
    该写法通常会与描述符搭配起来,使这些属性可以了解自己在外围类的使用方式
应用场景:
定义某个类,表示客户数据库中的某一行。还希望该类的相关属性与数据库表
的没一列之间,建立对应关系

2 描述符
描述符类: 可以提供__get__和__set__方法
原理: 
exam.writingGrade = 40
会被转换为
Exam.__dict__['writingGrade'].__set__(exam, 40)
获取属性会被转换为
Exam.__dict__['writingGrade'].__get__(exam, Exam)
之所以存在上述转换: 是因为object类的__getattribute__方法

类实例没有某个属性 ---> 在类中查找同名属性(
类属性,如果实现了__get__和__set__方法,则认为该对象遵循描述符协议)

3 总结
元类可以在类完全定义好之前,修改该类的属性;
描述符与元类组合后,可以对行为作出修饰,不使用weakref就避免内存泄露

参考:
Effectiv Python 编写高质量Python代码的59个有效方法
'''

'''
描述符类: 把属性与列名联系起来。
    列的名称已经保存到了Field描述符中。
'''
class Field2(object):
    def __init__(self, name):
        self.name = name
        self.internalName = "_" + self.name

    def __get__(self, instance, instance_type):
        if instance is None:
            return self
        return getattr(instance, self.internalName, '')

    def __set__(self, instance, value):
        setattr(instance, self.internalName, value)


class Customer(object):
    # Class attributes
    first_name = Field2('first_name')
    last_name = Field2('last_name')
    prefix = Field2('prefix')
    suffix = Field2('suffix')


def useCustomer2():
    customer = Customer()
    print "Before: {value}, {mydict}".format(
        value=repr(customer.first_name),
        mydict=customer.__dict__
    )
    customer.first_name = 'Chen'
    print "After: {value}, {mydict}".format(
        value=repr(customer.first_name),
        mydict=customer.__dict__
    )


class Field(object):
    def __init__(self):
        # 下面的属性已经被元类设置了
        self.name = None
        self.internalName = None

    def __get__(self, instance, instance_type):
        if instance is None:
            return self
        return getattr(instance, self.internalName, '')

    def __set__(self, instance, value):
        return setattr(instance, self.internalName, value)


class Meta(type):
    def __new__(meta, name, bases, class_dict):
        for key, value in class_dict.items():
            if isinstance(value, Field):
                value.name = key
                value.internalName = "_" + key
        cls = type.__new__(meta, name, bases, class_dict)
        return cls


class DatabaseRow(object):
    __metaclass__ = Meta


class BetterCustomer(DatabaseRow):
    first_name = Field()
    last_name = Field()
    prefix = Field()
    suffix = Field()


def useCustomer():
    customer = Customer()
    print "Before: {value}, {mydict}".format(
        value=repr(customer.first_name),
        mydict=customer.__dict__
    )
    customer.first_name = 'Chen'
    print "After: {value}, {mydict}".format(
        value=repr(customer.first_name),
        mydict=customer.__dict__
    )


def process():
    useCustomer()


if __name__ == "__main__":
    process() 

猜你喜欢

转载自blog.csdn.net/qingyuanluofeng/article/details/88940865