此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。