【问题标题】:Can a Python function remember its previous outputs? [duplicate]Python 函数能记住它之前的输出吗? [复制]
【发布时间】:2020-04-27 16:04:05
【问题描述】:

有没有一种方法可以让函数记住其先前的输出并在下次调用该函数时使用该值?例如,假设有一个函数 runningTotal 带有一个参数 x,它在第一次调用 runningTotal 时返回 x,但之后的每次调用都返回 x + prevOutput。有没有办法在python中编写这样的函数?

我知道这可以通过在函数中使用全局变量或将以前的值保存到新变量来轻松实现,但如果可能的话,我想避免使用这些解决方案。我正在寻找替代解决方案的原因是因为这是我正在与其他人合作的程序中的一个功能,我希望避免创建比已经建立的更多的全局变量。

【问题讨论】:

  • 是的:generators
  • 从技术上讲,生成器不仅仅是记住之前的输出。它们保持整个函数状态;这样您就可以在后续调用中访问所有局部变量的值。
  • 这是一个很模糊的问题,请说的更具体点,guidance
  • 你可以使用函数闭包。见Simulate static variables in python with closures
  • This question 包含其他方式(除了闭包)来模拟静态变量(附加到函数的变量,在函数调用之间保持其状态)。

标签: python python-3.x function


【解决方案1】:

是的,但是为了避免过多的hackery 或 GLOBAL 变量,我们可能想要使用一个类。 在 python 中,一个类可以被视为在名为__call__ 的类中具有魔术函数(方法)的函数。

您的问题可能写得更好:在 python 中具有内部状态的函数的最佳方法是什么?

假设我们使用全局变量定义了 runningTotal 函数:

TOTAL = 0
def runningTotal(inc):
    global TOTAL
    TOTAL += inc
    return TOTAL

答案 好的,让我们定义一个行为方式与上述函数相同但没有全局变量的类:


class StatefulFunction:
    running_total = 0

    def __call__(self, inc):
        self.running_total += inc
        return self.running_total


# create the stateful function variable
runningTotal = StatefulFunction()

# Use the stateful function
runningTotal(1)
# outputs: 1
runningTotal(5)
# outputs: 6

完成同样事情的另一种方法是使用计数器字典

from collections import Counter
counter = Counter()
counter['runningTotal'] += 1
# in another part of the program
counter['runningTotal'] += 5

输出将是:

print(counter)
Counter({'runningTotal': 6})

【讨论】:

  • 这不是计数器的好用例
  • 你能详细说明原因吗?
【解决方案2】:

虽然可以按照您的要求进行操作,但这不是一个好主意。正如@JohnColeman 指出的那样,Simulate static variables in python with closures

但是为什么不创建一个类呢?

class Accumulator:
    total = 0

    @classmethod
    def add(cls, x):
        cls.total += x
        return cls.total


print(Accumulator.add(1))
print(Accumulator.add(2))
print(Accumulator.add(3))

结果:

1
3
6

您可以设置一个生成器来维护状态并向其发送值,正如@HeapOverflow 所建议的那样:

def get_running_total():
    def _running_total():
        value = 0
        while True:
            value += yield value
    # get a generator instance
    generator = _running_total()
    # set it up to wait for input
    next(generator)
    # return the send method on the generator
    return generator.send


# you can get a generator that functions similar to the Accumulator method
running_total = get_running_total()
print(running_total(1))   # prints 1
print(running_total(2))   # prints 3
print(running_total(3))   # prints 6

【讨论】:

  • 你是对的 - 我的评论太尖锐了,虽然我认为这个解决方案仍然有点老套,但它肯定更接近 OP 的要求。我会更新我的答案。
  • 其实又做了一次更新,可以把设置封装在函数里面,我觉得这个方案更干净(而且可以复用)。
  • 我想我也有这样的版本,但认为它不如更普通的this。我想说我主要写了一个生成器解决方案来练习它(尤其是发送),因为你说它不起作用:-P
猜你喜欢
  • 1970-01-01
  • 2013-04-02
  • 2011-03-04
  • 2021-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-25
相关资源
最近更新 更多