这个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 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)
其他回答
鉴于这个问题,我可以提出另一个可能更好用的替代方案,对方法和函数看起来都是一样的:
@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
这个回答建立在@claudiu的回答之上。
我发现我的代码变得越来越不清晰,而我一直都很清楚 当我要访问静态变量时,可以在函数名前面加上。
也就是说,在我的函数代码中,我更喜欢这样写:
print(statics.foo)
而不是
print(my_function_name.foo)
所以,我的解决方案是:
向函数中添加静态属性 在函数作用域中,添加一个局部变量statics作为my_function.statics的别名
from bunch import *
def static_vars(**kwargs):
def decorate(func):
statics = Bunch(**kwargs)
setattr(func, "statics", statics)
return func
return decorate
@static_vars(name = "Martin")
def my_function():
statics = my_function.statics
print("Hello, {0}".format(statics.name))
备注
我的方法使用一个名为Bunch的类,它是一个字典,支持 属性风格的访问,一种JavaScript(参见2000年左右关于它的原始文章)
它可以通过pip install bunch安装
也可以这样手写:
class Bunch(dict):
def __init__(self, **kw):
dict.__init__(self,kw)
self.__dict__ = self
其他答案已经演示了您应该如何做到这一点。这里有一种方法你不应该:
>>> def foo(counter=[0]):
... counter[0] += 1
... print("Counter is %i." % counter[0]);
...
>>> foo()
Counter is 1.
>>> foo()
Counter is 2.
>>>
默认值仅在函数第一次求值时初始化,而不是每次执行时初始化,因此可以使用列表或任何其他可变对象来存储静态值。
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__()方法来实现可调用。
许多人已经建议测试“hasattr”,但有一个更简单的答案:
def func():
func.counter = getattr(func, 'counter', 0) + 1
没有try/except,没有测试hasattr,只有默认的getattr。