看本文之前蛮艰,可以先閱讀Python中的lazy property郑什,概念與用法在上述文章中有比較詳細(xì)的介紹功炮,本文是對(duì)其未講解清晰地方的具體分析隔缀。
描述符+類(lèi)裝飾器實(shí)現(xiàn)
class LazyProperty(object):
def __init__(self, func):
# 初始化func為serverHost函數(shù)
self.func = func
def __get__(self, instance, owner):
if instance is None:
return self
else:
value = self.func(instance)
# 會(huì)將結(jié)果值通過(guò)setattr方法存入到instance實(shí)例的__dict__中
setattr(instance, self.func.__name__, value)
return value
class ConfigHandler:
def __init__(self):
pass
# 返回一個(gè)LazyProperty實(shí)例
@LazyProperty
def serverHost(self):
return os.environ.get("HOST", setting.HOST)
setting = namedtuple("setting", ["HOST"])
setting.HOST = "g"
# 測(cè)試一
a = ConfigHandler()
print(a.__dict__)
# 1. 注解先是創(chuàng)建了LazyProperty(serverHost)的實(shí)例
# 2. 再是語(yǔ)法糖進(jìn)行了賦值serverHost = LazyProperty(serverHost)
# 3. 當(dāng)?shù)谝淮芜M(jìn)行調(diào)用的時(shí)候, instance = configHandler**實(shí)例**, self.func(instance實(shí)例) == 調(diào)用serverHost(instance實(shí)例)從而獲得了真正值value煮剧。而之后的 setattr處將self實(shí)例的__dict__中添加了serverHost-value闻镶,再次訪問(wèn)self.serverHost時(shí), 已經(jīng)不再是函數(shù), 而是value值(serverHost不再?gòu)腃onfigHandler.__dict__中取, 而是實(shí)例a.__dict__中取)
print(a.serverHost)
print("say")
print(a.__dict__)
# 測(cè)試二
# 如果先執(zhí)行類(lèi)的__dict__能看到類(lèi)的serverHost是一個(gè)**描述器對(duì)象實(shí)例**=> 'serverHost': <__main__.LazyProperty object at 0x0000020A1AEB7FD0>
print(ConfigHandler.__dict__)
# 通過(guò)__dir__能見(jiàn)到serverHost為實(shí)例的一個(gè)方法
print(a.__dir__())
# 此時(shí)a.__dict__為空
print(a.serverHost)
# 等到調(diào)用過(guò)a.serverHost后可以發(fā)現(xiàn)a.__dict__中多了serverHost
print(a.__dict__)
# 由于實(shí)例__dict__會(huì)優(yōu)先于類(lèi)的__dict__使用甚脉,所以直接返回了value值
重點(diǎn):
- 跟[
print(t.des)
](#3.object.__get__(self, instance, owner)
)會(huì)觸發(fā)t.des指向的descriptor實(shí)例的__get__
一樣,通過(guò)類(lèi)__dict__["serverHost"]
铆农,其也是個(gè)描述器實(shí)例牺氨,因此也會(huì)觸發(fā)LazyProperty object的__get__
- 實(shí)例
__dict__
會(huì)優(yōu)先于類(lèi)的__dict__
使用,如果實(shí)例__dict__
找不到墩剖,會(huì)往上類(lèi)__dict__
找
修飾符(方法裝飾器)
def lazy_property(func):
# 創(chuàng)建protected屬性
attr_name = "_lazy_" + func.__name__
@property
def _lazy_property(self):
# print("done")
if not hasattr(self, attr_name):
# print("set")
setattr(self, attr_name, func(self))
return getattr(self, attr_name)
return _lazy_property
class Circle(object):
def __init__(self, radius):
self.radius = radius
@lazy_property
def area(self):
return 3.14 * self.radius ** 2
# 當(dāng)解析Circle類(lèi)猴凹、定義area方法的時(shí)候,會(huì)將Circle.area = @property修飾的_lazy_property函數(shù)
c = Circle(4)
print('before calculate area')
print(c.__dict__)
# 當(dāng)調(diào)用c.area時(shí)岭皂,會(huì)輸出done, 此時(shí)會(huì)執(zhí)行_lazy_property內(nèi)的具體函數(shù), 此次會(huì)進(jìn)行setattr
print(c.area)
# 此次不會(huì)調(diào)用setattr
print(c.area)
print('after calculate area')
print(c.__dict__)
c.radius = 5