此C / C ++代碼的慣用Python等效項是什麼? python
void foo() { static int counter = 0; counter++; printf("counter is %d\n", counter); }
具體來講,如何在函數級別(而不是類級別)實現靜態成員? 並將函數放入類中是否會發生任何變化? app
我我的更喜歡如下裝飾器。 給每一個人本身。 ide
def staticize(name, factory): """Makes a pseudo-static variable in calling function. If name `name` exists in calling function, return it. Otherwise, saves return value of `factory()` in name `name` of calling function and return it. :param name: name to use to store static object in calling function :type name: String :param factory: used to initialize name `name` in calling function :type factory: function :rtype: `type(factory())` >>> def steveholt(z): ... a = staticize('a', list) ... a.append(z) >>> steveholt.a Traceback (most recent call last): ... AttributeError: 'function' object has no attribute 'a' >>> steveholt(1) >>> steveholt.a [1] >>> steveholt('a') >>> steveholt.a [1, 'a'] >>> steveholt.a = [] >>> steveholt.a [] >>> steveholt('zzz') >>> steveholt.a ['zzz'] """ from inspect import stack # get scope enclosing calling function calling_fn_scope = stack()[2][0] # get calling function calling_fn_name = stack()[1][3] calling_fn = calling_fn_scope.f_locals[calling_fn_name] if not hasattr(calling_fn, name): setattr(calling_fn, name, factory()) return getattr(calling_fn, name)
這是一個徹底封裝的版本,不須要外部初始化調用: 函數
def fn(): fn.counter=vars(fn).setdefault('counter',-1) fn.counter+=1 print (fn.counter)
在Python中,函數是對象,咱們能夠經過特殊屬性__dict__
簡單地向其添加或修改爲員變量。 內置的vars()
返回特殊屬性__dict__
。 測試
編輯:請注意,與替代的try:except AttributeError
答案不一樣,經過這種方法,變量將始終爲初始化後的代碼邏輯作好準備。 我認爲如下方法的try:except AttributeError
替代方法將減小DRY和/或具備笨拙的流程: ui
def Fibonacci(n): if n<2: return n Fibonacci.memo=vars(Fibonacci).setdefault('memo',{}) # use static variable to hold a results cache return Fibonacci.memo.setdefault(n,Fibonacci(n-1)+Fibonacci(n-2)) # lookup result in cache, if not available then calculate and store it
EDIT2:僅當從多個位置調用該函數時,才建議使用上述方法。 相反,若是隻在一個地方調用該函數,則最好使用nonlocal
: spa
def TheOnlyPlaceStaticFunctionIsCalled(): memo={} def Fibonacci(n): nonlocal memo # required in Python3. Python2 can see memo if n<2: return n return memo.setdefault(n,Fibonacci(n-1)+Fibonacci(n-2)) ... print (Fibonacci(200)) ...
還能夠考慮: code
def foo(): try: foo.counter += 1 except AttributeError: foo.counter = 1
推理: 對象
ask for forgiveness not permission
) if
分支(認爲StopIteration異常) 在這個問題的提示下,我能夠提出另外一種選擇,它可能會更好用,而且對於方法和函數來講都同樣: ci
@static_var2('seed',0) def funccounter(statics, add=1): statics.seed += add return statics.seed print funccounter() #1 print funccounter(add=2) #3 print funccounter() #4 class ACircle(object): @static_var2('seed',0) def counter(statics, self, add=1): statics.seed += add return statics.seed c = ACircle() print c.counter() #1 print c.counter(add=2) #3 print c.counter() #4 d = ACircle() print d.counter() #5 print d.counter(add=2) #7 print d.counter() #8
若是您喜歡這種用法,請執行如下操做:
class StaticMan(object): def __init__(self): self.__dict__['_d'] = {} def __getattr__(self, name): return self.__dict__['_d'][name] def __getitem__(self, name): return self.__dict__['_d'][name] def __setattr__(self, name, val): self.__dict__['_d'][name] = val def __setitem__(self, name, val): self.__dict__['_d'][name] = val def static_var2(name, val): def decorator(original): if not hasattr(original, ':staticman'): def wrapped(*args, **kwargs): return original(getattr(wrapped, ':staticman'), *args, **kwargs) setattr(wrapped, ':staticman', StaticMan()) f = wrapped else: f = original #already wrapped getattr(f, ':staticman')[name] = val return f return decorator
不少人已經建議測試「 hasattr」,可是答案很簡單:
def func(): func.counter = getattr(func, 'counter', 0) + 1
沒有try / except,沒有測試hasattr,只有默認的getattr。