这个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);
}
具体来说,如何在函数级别实现静态成员,而不是在类级别?将函数放入类中会改变什么吗?
当前回答
另一个(不推荐!)对https://stackoverflow.com/a/279598/916373这样的可调用对象的扭曲,如果您不介意使用一个时髦的调用签名的话
class foo(object):
counter = 0;
@staticmethod
def __call__():
foo.counter += 1
print "counter is %i" % foo.counter
>>> foo()()
counter is 1
>>> foo()()
counter is 2
其他回答
你可以创建一个所谓的“函数对象”,并给它一个标准的(非静态的)成员变量,而不是创建一个具有静态局部变量的函数。
既然你给出了一个c++编写的例子,我将首先解释什么是c++中的“函数对象”。“函数对象”就是任何带有重载操作符()的类。类实例的行为类似于函数。例如,你可以写int x = square(5);即使square是一个对象(带有重载操作符()),从技术上讲也不是一个“函数”。你可以给一个函数对象任何你可以给一个类对象的特性。
# C++ function object
class Foo_class {
private:
int counter;
public:
Foo_class() {
counter = 0;
}
void operator() () {
counter++;
printf("counter is %d\n", counter);
}
};
Foo_class foo;
在Python中,我们也可以重载operator(),除非该方法被命名为__call__:
下面是一个类定义:
class Foo_class:
def __init__(self): # __init__ is similair to a C++ class constructor
self.counter = 0
# self.counter is like a static member
# variable of a function named "foo"
def __call__(self): # overload operator()
self.counter += 1
print("counter is %d" % self.counter);
foo = Foo_class() # call the constructor
下面是一个使用这个类的例子:
from foo import foo
for i in range(0, 5):
foo() # function call
打印到控制台的输出是:
counter is 1
counter is 2
counter is 3
counter is 4
counter is 5
如果你想让你的函数接受输入参数,你也可以将它们添加到__call__:
# FILE: foo.py - - - - - - - - - - - - - - - - - - - - - - - - -
class Foo_class:
def __init__(self):
self.counter = 0
def __call__(self, x, y, z): # overload operator()
self.counter += 1
print("counter is %d" % self.counter);
print("x, y, z, are %d, %d, %d" % (x, y, z));
foo = Foo_class() # call the constructor
# FILE: main.py - - - - - - - - - - - - - - - - - - - - - - - - - - - -
from foo import foo
for i in range(0, 5):
foo(7, 8, 9) # function call
# Console Output - - - - - - - - - - - - - - - - - - - - - - - - - -
counter is 1
x, y, z, are 7, 8, 9
counter is 2
x, y, z, are 7, 8, 9
counter is 3
x, y, z, are 7, 8, 9
counter is 4
x, y, z, are 7, 8, 9
counter is 5
x, y, z, are 7, 8, 9
我个人更喜欢下面的装饰。各有各的。
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)
其他解决方案将计数器属性附加到函数,通常使用复杂的逻辑来处理初始化。这对于新代码是不合适的。
在Python 3中,正确的方法是使用非局部语句:
counter = 0
def foo():
nonlocal counter
counter += 1
print(f'counter is {counter}')
有关非局部语句的规范,请参阅PEP 3104。
如果计数器是模块私有的,则应该将其命名为_counter。
根据丹尼尔的回答(补充):
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化。
使用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的文档。