这个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);
}
具体来说,如何在函数级别实现静态成员,而不是在类级别?将函数放入类中会改变什么吗?
当前回答
全局声明提供此功能。在下面的例子中(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"
其他回答
使用generator函数生成迭代器。
def foo_gen():
n = 0
while True:
n+=1
yield n
然后像这样使用它
foo = foo_gen().next
for i in range(0,10):
print foo()
如果你想要一个上限:
def foo_gen(limit=100000):
n = 0
while n < limit:
n+=1
yield n
如果迭代器终止(如上面的例子),您也可以直接遍历它,如
for i in foo_gen(20):
print i
当然,在这些简单的情况下,最好使用xrange:)
这是yield statement的文档。
有点相反,但这应该是有效的:
def foo():
foo.counter += 1
print "Counter is %d" % foo.counter
foo.counter = 0
如果你想让计数器初始化代码在顶部而不是底部,你可以创建一个装饰器:
def static_vars(**kwargs):
def decorate(func):
for k in kwargs:
setattr(func, k, kwargs[k])
return func
return decorate
然后像这样使用代码:
@static_vars(counter=0)
def foo():
foo.counter += 1
print "Counter is %d" % foo.counter
它仍然需要你使用foo。前缀,不幸的是。
(图片来源:@ony)
使用函数的属性作为静态变量有一些潜在的缺点:
每次要访问变量时,都必须写出函数的全名。 外部代码可以很容易地访问该变量并打乱值。
第二个问题的惯用python可能会用前导下划线来命名变量,以表明它不应该被访问,同时在事后保持它的可访问性。
使用闭包
另一种选择是使用词法闭包的模式,python 3中的nonlocal关键字支持这种模式。
def make_counter():
i = 0
def counter():
nonlocal i
i = i + 1
return i
return counter
counter = make_counter()
遗憾的是,我不知道如何将这个解决方案封装到装饰器中。
使用内部状态参数
另一种选择可能是使用未记录的参数作为可变值容器。
def counter(*, _i=[0]):
_i[0] += 1
return _i[0]
这是可行的,因为默认参数是在定义函数时计算的,而不是在调用函数时计算的。
更清洁的方法可能是使用容器类型而不是列表,例如:
def counter(*, _i = Mutable(0)):
_i.value += 1
return _i.value
但我不知道内置类型,清楚地传达的目的。
米格尔·安吉洛的自我重新定义解决方案甚至可以不需要任何装饰:
def fun(increment=1):
global fun
counter = 0
def fun(increment=1):
nonlocal counter
counter += increment
print(counter)
fun(increment)
fun() #=> 1
fun() #=> 2
fun(10) #=> 12
第二行必须进行调整,以获得有限的范围:
def outerfun():
def innerfun(increment=1):
nonlocal innerfun
counter = 0
def innerfun(increment=1):
nonlocal counter
counter += increment
print(counter)
innerfun(increment)
innerfun() #=> 1
innerfun() #=> 2
innerfun(10) #=> 12
outerfun()
装饰器的优点是,你不必额外注意你的施工范围。
def staticvariables(**variables):
def decorate(function):
for variable in variables:
setattr(function, variable, variables[variable])
return function
return decorate
@staticvariables(counter=0, bar=1)
def foo():
print(foo.counter)
print(foo.bar)
就像上面vincent的代码一样,这将被用作函数装饰器,静态变量必须以函数名作为前缀访问。这段代码的优点(尽管每个人都可以聪明地看出这一点)是你可以有多个静态变量,并以更常规的方式初始化它们。