Python中的静态变量?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26630821/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Static variable in Python?
提问by kuskmen
In C++ we have static keyword which in loops is something like this:
在 C++ 中,我们有 static 关键字,它在循环中是这样的:
for(int x=0; x<10; x++)
{
for(int y=0; y<10; y++)
{
static int number_of_times = 0;
number_of_times++;
}
}
static here makes number_of_timesinitialized once. How can I do same thing in python 3.x?
这里的静态使number_of_times初始化一次。我如何在 python 3.x 中做同样的事情?
EDIT: Since most of the people got confused I would like to point out that the code I gave is just example of static usage in C++. My real problem is that I want to initialize only ONE time variable in function since I dont want it to be global(blah!) or default parameter..
编辑:由于大多数人感到困惑,我想指出我提供的代码只是 C++ 中静态用法的示例。我真正的问题是我只想在函数中初始化一个时间变量,因为我不希望它是全局的(等等!)或默认参数..
采纳答案by bruno desthuilliers
Assuming what you want is "a variable that is initialised only once on first function call", there's no such thing in Python syntax. But there are ways to get a similar result:
假设您想要的是“在第一次函数调用时仅初始化一次的变量”,Python 语法中没有这样的东西。但是有一些方法可以获得类似的结果:
1 - Use a global. Note that in Python, 'global' really means 'global to the module', not 'global to the process':
1 - 使用全局。请注意,在 Python 中,“全局”实际上意味着“模块的全局”,而不是“进程的全局”:
_number_of_times = 0
def yourfunc(x, y):
global _number_of_times
for i in range(x):
for j in range(y):
_number_of_times += 1
2 - Wrap you code in a class and use a class attribute (ie: an attribute that is shared by all instances). :
2 - 将您的代码包装在一个类中并使用一个类属性(即:所有实例共享的属性)。:
class Foo(object):
_number_of_times = 0
@classmethod
def yourfunc(cls, x, y):
for i in range(x):
for j in range(y):
cls._number_of_times += 1
Note that I used a classmethodsince this code snippet doesn't need anything from an instance
请注意,我使用了 aclassmethod因为此代码片段不需要实例中的任何内容
3 - Wrap you code in a class, use an instance attribute and provide a shortcut for the method:
3 - 将您的代码包装在一个类中,使用实例属性并为该方法提供快捷方式:
class Foo(object):
def __init__(self):
self._number_of_times = 0
def yourfunc(self, x, y):
for i in range(x):
for j in range(y):
self._number_of_times += 1
yourfunc = Foo().yourfunc
4 - Write a callable class and provide a shortcut:
4 - 编写一个可调用的类并提供一个快捷方式:
class Foo(object):
def __init__(self):
self._number_of_times = 0
def __call__(self, x, y):
for i in range(x):
for j in range(y):
self._number_of_times += 1
yourfunc = Foo()
4 bis - use a class attribute and a metaclass
4 之二 - 使用类属性和元类
class Callable(type):
def __call__(self, *args, **kw):
return self._call(*args, **kw)
class yourfunc(object):
__metaclass__ = Callable
_numer_of_times = 0
@classmethod
def _call(cls, x, y):
for i in range(x):
for j in range(y):
cls._number_of_time += 1
5 - Make a "creative" use of function's default arguments being instantiated only once on module import:
5 - “创造性地”使用在模块导入时仅实例化一次的函数的默认参数:
def yourfunc(x, y, _hack=[0]):
for i in range(x):
for j in range(y):
_hack[0] += 1
There are still some other possible solutions / hacks, but I think you get the big picture now.
还有一些其他可能的解决方案/技巧,但我认为您现在已经了解了大局。
EDIT: given the op's clarifications, ie "Lets say you have a recursive function with default parameter but if someone actually tries to give one more argument to your function it could be catastrophic", it looks like what the OP really wants is something like:
编辑:鉴于操作的澄清,即“假设您有一个带有默认参数的递归函数,但如果有人实际上试图为您的函数提供更多参数,则可能是灾难性的”,看起来 OP 真正想要的是这样的:
# private recursive function using a default param the caller shouldn't set
def _walk(tree, callback, level=0):
callback(tree, level)
for child in tree.children:
_walk(child, callback, level+1):
# public wrapper without the default param
def walk(tree, callback):
_walk(tree, callback)
Which, BTW, prove we really had Yet Another XY Problem...
顺便说一句,这证明我们确实遇到了另一个 XY 问题......
回答by parchment
You can create a closure with nonlocalto make them editable (python 3.x only). Here's an example of a recursive function to calculate the length of a list.
您可以创建一个闭包nonlocal以使其可编辑(仅限 python 3.x)。这是计算列表长度的递归函数的示例。
def recursive_len(l):
res = 0
def inner(l2):
nonlocal res
if l2:
res += 1
inner(l2[1:])
inner(l)
return res
Or, you can assign an attribute to the function itself. Using the trick from here:
或者,您可以为函数本身分配一个属性。使用这里的技巧:
def fn(self):
self.number_of_times += 1
fn.func_defaults = (fn,)
fn.number_of_times = 0
fn()
fn()
fn()
print (fn.number_of_times)
回答by frlan
You can also use the global keyword:
您还可以使用 global 关键字:
def main(args):
for i in xrange(10):
print i
global tmp
tmp = i
But be careful... I most cases it will add more issues than it solves.
但是要小心......我在大多数情况下它会增加更多的问题而不是它解决的问题。
回答by Mark Reed
Python doesn't have static variables by design. For your example, and use within loop blocks etc. in general, you just use a variable in an outer scope; if that makes it too long-lived, it might be time to consider breaking up that function into smaller ones.
Python 在设计上没有静态变量。对于您的示例,通常在循环块等中使用,您只需在外部范围内使用变量;如果这使它的寿命太长,那么可能是时候考虑将该功能分解为较小的功能了。
For a variable that continues to exist between calls to a function, that's just reimplementing the basic idea of an object and a method on that object, so you should make one of those instead.
对于在函数调用之间继续存在的变量,这只是重新实现了对象的基本思想和该对象上的方法,因此您应该创建其中一个。
回答by matsjoyce
The another function-based way of doing this in python is:
在 python 中执行此操作的另一种基于函数的方法是:
def f(arg, static_var=[0]):
static_var[0] += arg
As the static_varobject is initialised at the function definition, and then reused for all the calls, it will act like a static variable. Note that you can't just use an int, as they are immutable.
由于static_var对象在函数定义时初始化,然后在所有调用中重用,因此它将像静态变量一样工作。请注意,您不能只使用int,因为它们是不可变的。
>>> def f(arg, static_var=[0]):
... static_var[0] += arg
... print(static_var[0])
...
>>> f(1)
1
>>> f(2)
3
>>> f(3)
6
回答by nexcvon
Use defaultdict:
使用defaultdict:
from collections import defaultdict
static = defaultdict(lambda: 0)
def myfunc():
for x in range(10):
for y in range(10):
static['number_of_times'] += 1

