如何在函数中保存状态?

问题描述 投票:0回答:3

使用类时,我可以使用属性保留状态:

class Hello:

    def __init__(self):
        self.hello = 1

    def add_one(self):
        if self.hello < 3:
            self.hello += 1
        else:
            self.hello = 1

h = Hello()
for _ in range(5):
    h.add_one()
    print(h.hello)

# output
2
3
1
2
3

在调用

h.add_one()
之间,状态保存在
h.hello
中。

函数中是否有等效的机制?类似的东西

def add_one():
    a_special_kind_of_variable_which_is_not_reinitialized hello
    if hello_is_not_initialized:
        hello = 1
    if hello < 3:
        hello += 1
    else:
        hello = 1
    return hello

for _ in range(5):
    print(add_one())

# same output as above
  • 使用全局变量将是一个解决方案,但我想避免这种情况。
  • 将返回值传回函数以强制状态是另一种选择,但我希望有一种方法可以在没有外部依赖的情况下将状态保留在函数内。
python python-3.x variables scope
3个回答
6
投票

Python 没有 C 风格的静态变量。但是,您可以使用闭包来模拟它们。

def make_add_one():
    x = 0
    def _():
        nonlocal x
        if x < 3:
           x += 1
        else:
            x = 1
        return x
    return _

add_one = make_add_one()

for _ in range(5):
    print(add_one())

对象(数据与函数)和闭包(函数与数据)之间存在二元性;与 Carcigenicate 定义的 类相比(稍作修改):

class AddOne:
    def __init__(self):
        self.hello = 0

    def __call__(self):
        if self.hello < 3:
            self.hello += 1
        else:
            self.hello = 1
        return self.hello

add_one = AddOne()
for _ in range(5):
    print(add_one())

可以看到以下对应关系:

  • AddOne
    ↔ 外部函数
    make_add_one
  • 实例
    AddOne()
    ↔ 内部函数
    make_add_one()
  • 实例属性
    AddOne().hello
    ↔ 非局部变量
    hello
    内部
    make_add_one

2
投票

您可以通过实现

__call__
:

来使类的实例类似于函数
class Hello:

    def __init__(self):
        self.hello = 1

    def __call__(self):
        if self.hello < 3:
            self.hello += 1
        else:
            self.hello = 1

h = Hello()
h()  # Works now

尽管如此,这只改变了调用语法。这基本上仍然是您的一流示例。

无论如何,拥有“函数实例”可能是一个更安全的设置。测试一个不具有来自对其执行的其他操作的永久持久状态的函数会更容易。为了干净地测试它,您只需要创建一个新实例,而使用“全局函数”,它可能会意外地受到您之前对其所做的其他操作的影响。


1
投票

您可以向函数添加属性,因为它们是对象:

def add_one():
    if not hasattr(add_one, 'hello'):
        add_one.hello = 1
    if add_one.hello < 3:
        add_one.hello += 1
    else:
        add_one.hello = 1
    return add_one.hello


for _ in range(5):
    print(add_one())

输出

2
3
1
2 
3
© www.soinside.com 2019 - 2024. All rights reserved.