Python中与Matlab的persistent相当的功能是什么?

5
可能是重复问题:
Python中函数内静态变量的等价物是什么? 我尝试编写一个递归函数。它遍历一个向量并给出一个值,该值取决于当前值和先前的值。在Matlab中,我可以在函数内声明一个变量为persistent,并且该值在调用函数后存储在内存中,因此下一次调用函数从先前值开始。
这是我为简单移动平均值编写的内容:
def AvgFilter(x):
    if not firstRun:  # checks if runs for first time, i.e. firstRun is empty
        k = 1        # setup initial variables if run for first time
        prevAvg = 0  # prevAvg - the average calculated during last call
        firstRun = 1 # only for initialisation
    alpha = (k-1)/k  
    avg = alpha * prevAvg + (1 - alpha)*x
    prevAvg = avg
    k = k + 1    
    return avg

我需要在函数调用之间记住变量 kprevAvgfirstRun。我读到可以通过装饰器来实现,我尝试在函数前设置 @counter 来实现它,但不确定该如何实现。装饰器是唯一的方法吗(没有找到其他方法)?如何编写计数器函数来存储我的变量?我有点担心后来使用更复杂的递归时,我会完全迷失在装饰器的概念中。

1
请查看:https://dev59.com/oHVC5IYBdhLWcg3wfhGL - Xyand
3个回答

5
听起来像是要用到生成器!生成器让你可以假装在循环中一次计算一个值,但是实际上它会暂停执行并在你调用yield时返回一个值。
def AvgFilter():
    k = 1
    avg = 0
    while True:
        alpha = (k-1)/float(k)
        x = yield avg # yield/return the old average, and get the new input value
        avg = alpha * avg + (1 - alpha)*x
        k = k + 1

f = AvgFilter()
print f.next()
print f.send(1)
print f.send(2)
print f.send(20)
print f.send(20)

# 0
# 1.0
# 1.5
# 7.66666666667
# 10.75

2
您可以采用以下方式之一:
  • 使用对象并将这些变量存储在该对象中,在函数调用之间重复使用相同的对象。
  • 使用全局变量(强烈不建议!)
  • 使用生成器(请参见jtbandes的回答)
以下是一个示例:
class AvgFilter(object):
    def __init__(self):
        self.k = 1
        self.avg = 0

    def run(x):
        alpha = float(self.k-1) / self.k  
        self.avg = alpha * self.avg + (1 - alpha)*x
        self.k +=1
        return self.avg

我无法使其正常工作,因为出现了错误 AttributeError: 'AvgFilter' object has no attribute 'avg'。之后进行更正后,输出问题仍然不符合预期(Python 中的整数除法),但是这个思路是我所需要的。 - tomasz74
@tomasz74 是的,你说得对,我会修改需要修改的位! - Thomas Orozco

2
感谢@Thomas Orozco和@jtbandes提供的答案。经过数日努力,我终于将代码实现了想要的效果。以下是代码及一些测试结果:
x = [10,2,30,4,50]
class avgFil2(object):
    def __init__(self):
        self.avg = 0
        self.k = 1.0
    def __call__(self, x):
        alpha = (self.k-1.0)/self.k  
        self.avg = alpha * self.avg + (1 - alpha)*x
        self.k +=1
       return self.avg

def simpleTest(x = x):     
    average = []
    avg = avgFil2()               # new variable and creation of instance (all initialisation)
    for i in range(len(x)):
        print 'input %f' % x[i] 
        print 'before change avg.avg=%f, k=%f' % (avg.avg, avg.k)   
        average.append(avg(x[i])) # class is called here, so all changes going on
        print 'after change avg.avg=%f, k=%f' % (avg.avg, avg.k)  
        print 'The output average is %f' % average[i]

simpleTest()

这个代码与Matlab非常不同,但很好。重要的陷阱是将k=1初始化为int不是float,因为除法会得出整数,导致结果为零。另一件事是我必须初始化为'self.k'而不是'k',否则会出现错误。生成器可能也可以使用,但我喜欢class解决方案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接