# -*- 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()