这个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中(到目前为止没有提到的一种方法是使用可变的默认参数),但这不是Python的惯用方法。只需要使用一个类。
如果您的使用模式合适,也可以使用生成器。
其他回答
Soulution n +=1
def foo():
foo.__dict__.setdefault('count', 0)
foo.count += 1
return foo.count
你可以创建一个所谓的“函数对象”,并给它一个标准的(非静态的)成员变量,而不是创建一个具有静态局部变量的函数。
既然你给出了一个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
在尝试了几种方法后,我最终使用了@warvariuc的答案的改进版本:
import types
def func(_static=types.SimpleNamespace(counter=0)):
_static.counter += 1
print(_static.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"
鉴于这个问题,我可以提出另一个可能更好用的替代方案,对方法和函数看起来都是一样的:
@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