所以我很好奇下面樣式問題的更有經驗的python程序員的看法。假設我正在構建一個函數,它將逐行遍歷一個熊貓數據框或任何類似的用例,其中一個函數需要訪問其以前的狀態。似乎有至少四種方式在Python實現這一點:python中的習語:closure vs functor vs object
1)瓶蓋:
def outer():
previous_state = None
def inner(current_state) :
nonlocal previous_state
#do something
previous_state=current_state
return something
所以,如果你來自一個JavaScript的背景,這將毫無疑問很自然的你。在python中它也很自然,直到你需要訪問封閉範圍,當你最終完成像inner.__code__.co_freevars
這樣的操作時,它會給你封閉變量的名稱作爲一個元組,並找到一個元組的索引你想要的,然後去inner.__closure__[index].cell_contents
來獲得它的價值。不完全優雅,但我想這一點通常是隱藏範圍,所以它很有意義,應該很難達到。另一方面,它也感到有點奇怪,python使封閉函數成爲私有的,因爲它幾乎消除了與OOP語言相比私有變量的其他方式。
2)函子
def outer():
def inner(current_state):
#do something
inner.previous_state=current_state
return something
ret = inner
ret.previous_state=None
return ret
該「打開封閉的」,因爲現在封閉狀態是作爲函數的屬性完全可見。這是有效的,因爲函數實際上只是僞裝的對象。我傾向於這是最pythonic。其清晰,簡潔和可讀性強。
3)對象 這可能是最熟悉的OOP編程
class Calculator(Object) :
def __init__(self):
self.previous_state=None
def do_something(self, current_state) :
#do_something
self.previous_state = current_state
return something
這裏最大的con是,你往往有很多的類定義的結束了。在像Java這樣的完全OOP語言中,這很好,您可以使用接口等來管理這個語言,但是在鴨子語言中有許多簡單的類只是爲了傳遞需要一些狀態的函數似乎有點奇怪。
4)全局 - 我不會證明這一點,我特別希望避免污染全局命名空間
5)裝飾 - 這是一個弧線球的一點點,但你可以用裝飾來存儲部分狀態信息。
@outer
def inner(previous_state, current_state):
#do something
return something
def outer(inner) :
def wrapper(current_state) :
result = inner(wrapper.previous_state, current_state)
wrapper.previous_state = current_state
return result
ret = wrapper
ret.previous_state=None
return result
這種語法是最熟悉的我,但如果我現在請
func = inner
我真正得到
func = outer(inner)
,然後重複調用func()
行爲就像函子例。我其實最恨這種方式。在我看來,有一個非常不透明的語法,因爲很多時候調用inner(current_state)會給你相同的結果,或者它每次都會給你一個新裝飾的函數,所以它看起來很糟糕以這種方式使裝飾器將狀態添加到函數中。
那麼哪種方法是正確的?我在這裏錯過了什麼優點和缺點?
我不是很追隨爲什麼你認爲你需要通過'inner .__ closure__'來訪問封閉變量;名稱只會在該結構中結束,因爲您主動在內部函數* already *中使用它們。 '__closure__'結構真的是一個內部實現細節。 –
我會讓人們開發這個,但從經驗來看,python開發人員傾向於將類用於這種場景。或者當你不需要完全清晰的時候裝飾器,並且用'@'選擇好的語法。你不想使用'nonlocal'或'global'關鍵字。仿函數經常被關閉。 – Cyrbil
封閉的名字在這方面與當地人沒有什麼不同;你通常不會閱讀他們的當地人的功能,你爲什麼要在封閉的情況下做同樣的事情?如果您需要將該狀態暴露給函數以外的地方,請使用函子或類的方法。 –