这个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);
}
具体来说,如何在函数级别实现静态成员,而不是在类级别?将函数放入类中会改变什么吗?
当前回答
当然,这是一个老问题,但我想我可以提供一些更新。
看来性能论点已经过时了。 对于siInt_try和isInt_re2,相同的测试套件似乎给出了类似的结果。 当然,结果会有所不同,但这是在我的计算机上使用python 3.4.4的一次会话,使用Xeon W3550的内核4.3.01。 我已经运行了几次,结果似乎相似。 我将全局正则表达式移动到函数静态,但性能差异可以忽略不计。
isInt_try: 0.3690
isInt_str: 0.3981
isInt_re: 0.5870
isInt_re2: 0.3632
考虑到性能问题,try/catch似乎可以生成最适合未来和墙角情况的代码,所以可能只是将其包装在函数中
其他回答
根据丹尼尔的回答(补充):
class Foo(object):
counter = 0
def __call__(self, inc_value=0):
Foo.counter += inc_value
return Foo.counter
foo = Foo()
def use_foo(x,y):
if(x==5):
foo(2)
elif(y==7):
foo(3)
if(foo() == 10):
print("yello")
use_foo(5,1)
use_foo(5,1)
use_foo(1,7)
use_foo(1,7)
use_foo(1,1)
我想添加这一部分的原因是,静态变量不仅用于增加某个值,而且还用于检查静态变量是否等于某个值,作为一个现实生活中的例子。
静态变量仍然受到保护,并且仅在函数use_foo()的作用域内使用。
在这个例子中,调用foo()函数完全是(相对于相应的c++等效函数):
stat_c +=9; // in c++
foo(9) #python equiv
if(stat_c==10){ //do something} // c++
if(foo() == 10): # python equiv
#add code here # python equiv
Output :
yello
yello
如果类Foo被严格定义为一个单例类,那将是理想的。这将使它更加python化。
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__()方法来实现可调用。
全局声明提供此功能。在下面的例子中(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():
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)
使用装饰器和闭包
下面的装饰器可用于创建静态函数变量。它将声明的函数替换为函数本身的返回值。这意味着被修饰的函数必须返回一个函数。
def static_inner_self(func):
return func()
然后在返回另一个带有捕获变量的函数的函数上使用decorator:
@static_inner_self
def foo():
counter = 0
def foo():
nonlocal counter
counter += 1
print(f"counter is {counter}")
return foo
nonlocal是必需的,否则Python认为计数器变量是一个局部变量而不是一个捕获变量。Python之所以如此,是因为变量赋值counter += 1。函数中的任何赋值都会使Python认为该变量是局部变量。
如果你没有在内部函数中为变量赋值,那么你可以忽略非局部语句,例如,在这个函数中,我用来缩进字符串的行,在这个函数中,Python可以推断出变量是非局部的:
@static_inner_self
def indent_lines():
import re
re_start_line = re.compile(r'^', flags=re.MULTILINE)
def indent_lines(text, indent=2):
return re_start_line.sub(" "*indent, text)
return indent_lines
附注:有一个被删除的答案提出了同样的问题。我不知道作者为什么删掉它。 https://stackoverflow.com/a/23366737/195417