为什么Python没有静态变量?

时间:2009-02-26 23:28:09

标签: python

questions asking how to simulate static variables in python

此外,在网络上可以找到许多不同的解决方案来创建静态变量。 (虽然我还没有看到我喜欢的那个。)

为什么Python不支持方法中的静态变量?这被认为是unpythonic还是与Python的语法有关?

修改

我特意询问了为什么的设计决策,我没有提供任何代码示例,因为我想避免解释来模拟静态变量。

9 个答案:

答案 0 :(得分:76)

这个遗漏背后的想法是静态变量仅在两种情况下有用:当你真的应该使用一个类时,你何时应该使用一个生成器。

如果要将有状态信息附加到函数,您需要的是一个类。或许是一个简单的课程,但是仍然是一个阶级:

def foo(bar):
    static my_bar # doesn't work

    if not my_bar:
        my_bar = bar

    do_stuff(my_bar)

foo(bar)
foo()

# -- becomes ->

class Foo(object):
    def __init__(self, bar):
        self.bar = bar

    def __call__(self):
        do_stuff(self.bar)

foo = Foo(bar)
foo()
foo()

如果您希望每次调用函数的行为都会改变,那么您需要的是生成器:

def foo(bar):
    static my_bar # doesn't work

    if not my_bar:
        my_bar = bar

    my_bar = my_bar * 3 % 5

    return my_bar

foo(bar)
foo()

# -- becomes ->

def foogen(bar):
    my_bar = bar

    while True:
        my_bar = my_bar * 3 % 5
        yield my_bar

foo = foogen(bar)
foo.next()
foo.next()

当然,静态变量 对于快速和脏脚本非常有用,在这些脚本中,您不希望处理小型任务的大型结构的麻烦。但是在那里,你真的不需要global以外的任何东西 - 它看起来似乎很笨拙,但对于小型的一次性脚本来说还是可以的:

def foo():
    global bar
    do_stuff(bar)

foo()
foo()

答案 1 :(得分:19)

类的一个替代方法是函数属性:

def foo(arg):
    if not hasattr(foo, 'cache'):
        foo.cache = get_data_dict()
    return foo.cache[arg]

虽然一个班级可能更干净,但这种技术可能很有用,而且在我看来更好,然后是全球性的。

答案 2 :(得分:8)

在Python 3中,我将使用闭包:

def makefoo():
    x = 0
    def foo():
        nonlocal x
        x += 1
        return x
    return foo

foo = makefoo()

print(foo())
print(foo())

答案 3 :(得分:7)

我认为本地静态变量的大多数用法是模拟生成器,即具有一些执行某个进程迭代的函数,返回结果,但保留后续调用的状态。 Python使用yield命令非常优雅地处理它,因此似乎不需要静态变量。

答案 4 :(得分:5)

这是一个设计选择。

我认为Guido认为你并不经常需要它们,而且你从来没有真正需要它们:你总是可以只使用一个全局变量并告诉每个人保持他们的油腻的爪子。你的变量; - )

答案 5 :(得分:4)

对于缓存或memoization目的,装饰器可以用作优雅且通用的解决方案。

答案 6 :(得分:0)

答案与为什么没有人使用静态方法(即使它们存在)几乎相同。你有一个模块级命名空间,它的用途与类无关。

答案 7 :(得分:0)

一个不明智的选择:

您还可以使用函数默认值的定义时间评估的副作用:

def func(initial=0, my_static=[])
  if not my_static:
    my_static.append(initial)

   my_static[0] += 1
  return my_static[0]

print func(0), func(0), func(0)

真的丑陋且容易被颠覆,但是有效。使用global比这更清洁,imo。

答案 8 :(得分:-1)

从你的一条评论中说:“我想使用它们来缓存从磁盘加载的内容。我认为如果我可以将它们分配给函数,它会使实例更加混乱”

然后使用缓存类作为其他类的类或实例属性。这样,您可以使用完整的类功能集而不会混淆其他内容。此外,您还可以获得可重复使用的工具。

这表明在SO上总是能够说明问题,而不是要求特定的低级别解决方案(例如,缺少语言功能)。这样,有人可以更快地给你一个很好的答案,而不是关于模拟“静态”(古代语言的一个不赞成的特征,在我看来)的无休止的争论。

相关问题