Effective Python 读书笔记: 第32条: 用__getattr__、__getattribute__和__setattr__实现按需生成的属性

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

import os

'''
第32条: 用__getattr__、__getattribute__和__setattr__实现按需生成的属性


关键:
1 __getattr__
应用场景: 把数据库的行表示为Python对象,操作与行对应的对象时,需要直到这个数据库的结构
作用: 若某个类定义了__getattr__, 且无法在该类对象的实例字典中找到查询的属性,
系统就会调用这个方法

2 __getattribute__
特点: 即使属性字典里面已经有了该属性,也会调用__getattribute__方法
应用场景: 每次访问属性时,检查全局事务状态

3 __setattr__
作用: 可以拦截对属性的赋值操作

4 总结
1) 通过__getattr__和__setattr__可以实现延迟加载并保存对象的属性
2) __getattr__只会在待访问属性缺失时触发,而__getattribute__会在每次访问属性时触发
3) 若要在__getattribute__和__setattr__方法中访问属性,需要通过super()来避免无限第归

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

class LazyDB(object):
    def __init__(self):
        self.exists = 5

    def __getattr__(self, name):
        value = "Value for %s" % name
        setattr(self, name, value)
        return value


class LoggingLazyDB(LazyDB):
    def __getattr__(self, name):
        print "Called __gretattr__(%s)" % (name)
        return super(LoggingLazyDB, self).__getattr__(name)


class ValidaingDB(object):
    def __init__(self):
        self.exists = 5

    def __getattribute__(self, name):
        print "Called __getattribute__(%s)" % (name)
        try:
            return super(ValidaingDB, self).__getattribute__(name)
        except AttributeError:
            value = "Value for %s" % name
            setattr(self, name, value)
            return value


class MissingPropertyDB(object):
    def __getattr__(self, name):
        if name == 'bad_name':
            raise AttributeError("%s is missing" % name)


class SavingDB(object):
    def __setattr__(self, name, value):
        # Save data to the DB log
        super(SavingDB, self).__setattr__(name, value)


class LoggingSavingDB(SavingDB):
    def __setattr__(self, name, value):
        print "Called __setattr__(%s, %s)" % (name, value)
        super(LoggingSavingDB, self).__setattr__(name, value)


class DictionaryDB(object):
    def __init__(self, data):
        self._data = data

    def __getattribute__(self, name):
        dataDict = super(DictionaryDB, self).__getattribute__('_data')
        return dataDict[name]


def useGetattr():
    data = LazyDB()
    print "Before: {value}".format(
        value=data.__dict__
    )
    print "foo: {value}".format(
        value=data.foo
    )
    print "After: {value}".format(
        value=data.__dict__
    )
    data = LoggingLazyDB()
    print "#####################"
    print "exists: {value}".format(
        value=data.exists
    )
    print "foo: {value}".format(
        value=data.foo
    )
    print "foo: {value}".format(
        value=data.foo
    )
    print "################################"
    data = ValidaingDB()
    print "exists: {exists}".format(
        exists=data.exists
    )
    print "foo: {value}".format(
        value=data.foo
    )
    print "foo: {value}".format(
        value=data.foo
    )
    print "##################################"
    # data = MissingPropertyDB()
    # data.bad_name
    data = LoggingSavingDB()
    print "Before: {value}".format(
        value=data.__dict__
    )
    data.foo = 5
    print "After: {value}".format(
        value=data.__dict__
    )
    data.foo = 7
    print "Finally: {value}".format(
        value=data.__dict__
    )
    print "#############################"
    data = DictionaryDB({'foo': 3})
    print data.foo


def process():
    useGetattr()


if __name__ == "__main__":
    process() 

猜你喜欢

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