关于decorator:matlab的persistent的python等价物

Python's equivalent for Matlab's persistent

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
What is the Python equivalent of static variables inside a function?

我试着写一个递归函数。它迭代一个向量,并给出一个依赖于当前值和上一个值的值。在matlab中,我可以在函数内部声明一个变量为persistent,在调用函数后,该值存储在内存中,因此函数的下一个调用从前面的值开始。

这就是我开始计算简单移动平均线的原因:

1
2
3
4
5
6
7
8
9
10
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。我读到它可以通过decorator来实现,我试着在函数之前设置@counter,但不确定应该如何实现它。装饰师是唯一的方法吗(没有找到其他东西)?如何编写计数器函数来存储变量?我有点担心,以后使用更复杂的递归,我将完全失去装饰的想法。


听起来像是发电机的工作!生成器让您假装只是在循环中一次计算一个值,但它实际上会暂停执行,并在调用yield时返回一个值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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

多亏了@thomas orozco和@jtbandes几天后的回答,我终于找到了我想要的工作。代码和一些测试是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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.0初始化为float,而不是将k=1初始化为int,因为alpha将为零,因为除法将计算为整数。另一件事,我必须初始化为"self.k"而不是"k",因为它会给出错误。发电机也可能工作,但我喜欢class解决方案。


您可以执行以下操作:

  • 使用对象并将这些变量存储在对象中,在函数调用之间重用同一对象。
  • 使用全局变量(强烈建议!)
  • 使用发电机(见jtbandes的回答)

下面是一个例子:

1
2
3
4
5
6
7
8
9
10
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