这个C/ c++代码在Python中的等效代码是什么?
void foo()
{
static int counter = 0;
counter++;
printf("counter is %d\n", counter);
}
具体来说,如何在函数级别实现静态成员,而不是在类级别?将函数放入类中会改变什么吗?
这个C/ c++代码在Python中的等效代码是什么?
void foo()
{
static int counter = 0;
counter++;
printf("counter is %d\n", counter);
}
具体来说,如何在函数级别实现静态成员,而不是在类级别?将函数放入类中会改变什么吗?
当前回答
下面是一个完全封装的版本,不需要外部初始化调用:
def fn():
fn.counter=vars(fn).setdefault('counter',-1)
fn.counter+=1
print (fn.counter)
在Python中,函数是对象,我们可以简单地通过特殊属性__dict__向它们添加或修补成员变量。内置的vars()返回特殊属性__dict__。
EDIT:注意,与另一种try不同:除了AttributeError答案外,使用这种方法,变量将始终为初始化后的代码逻辑做好准备。我认为try:except AttributeError替代以下将不那么干和/或有尴尬的流程:
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:
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))
...
其他回答
全局声明提供此功能。在下面的例子中(python 3.5或更高版本使用“f”),counter变量在函数外部定义。在函数中将其定义为全局的,意味着函数外部的“全局”版本应该对函数可用。所以每次函数运行时,它都会修改函数外部的值,在函数外部保留它。
counter = 0
def foo():
global counter
counter += 1
print("counter is {}".format(counter))
foo() #output: "counter is 1"
foo() #output: "counter is 2"
foo() #output: "counter is 3"
你也可以考虑:
def foo():
try:
foo.counter += 1
except AttributeError:
foo.counter = 1
推理:
非常python化(“请求原谅而不是允许”) 使用异常(只抛出一次)而不是if分支(考虑StopIteration异常)
Python没有静态变量,但你可以通过定义一个可调用的类对象,然后将其用作函数来伪装它。也可以看看这个答案。
class Foo(object):
# Class variable, shared by all instances of this class
counter = 0
def __call__(self):
Foo.counter += 1
print Foo.counter
# Create an object instance of class "Foo," called "foo"
foo = Foo()
# Make calls to the "__call__" method, via the object's name itself
foo() #prints 1
foo() #prints 2
foo() #prints 3
注意,__call__使类(对象)的实例可以通过自己的名称调用。这就是为什么上面调用foo()会调用类的__call__方法。从文档中可以看到:
任意类的实例都可以通过在类中定义__call__()方法来实现可调用。
其他答案已经演示了您应该如何做到这一点。这里有一种方法你不应该:
>>> def foo(counter=[0]):
... counter[0] += 1
... print("Counter is %i." % counter[0]);
...
>>> foo()
Counter is 1.
>>> foo()
Counter is 2.
>>>
默认值仅在函数第一次求值时初始化,而不是每次执行时初始化,因此可以使用列表或任何其他可变对象来存储静态值。
可读性更强一点,但更冗长(Python的Zen:显式比隐式更好):
>>> def func(_static={'counter': 0}):
... _static['counter'] += 1
... print _static['counter']
...
>>> func()
1
>>> func()
2
>>>
请看这里,了解它是如何工作的。