【问题标题】:Python's equivalent for Matlab's persistent [duplicate]Python 等价于 Matlab 的持久性 [重复]
【发布时间】:2012-09-27 16:10:05
【问题描述】:

可能重复:
What is the Python equivalent of static variables inside a function?

我尝试编写一个递归函数。它遍历一个向量并给出一个取决于当前值和先前值的值。在 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

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

【问题讨论】:

标签: python decorator


【解决方案1】:

听起来像是generators 的工作!生成器让你假装你只是在循环中一次计算一个值,但它实际上会暂停执行并在你调用 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】:

    感谢@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.0 初始化为float 而不是将k=1 初始化为int,因为alpha 将为零,因为除法将计算为整数。另一件事,我必须初始化为'self.k'而不是'k',否则它会给出错误。生成器可能也可以工作,但我喜欢class 解决方案。

    【讨论】:

      【解决方案3】:

      您可以执行以下操作:

      • 使用对象并将这些变量存储在对象中,在函数调用之间重用同一个对象。
      • 使用全局变量(强烈反对!)
      • 使用生成器(参见 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中的int除法),但这个想法是我需要的
      • @tomasz74 是的,你确实是对的,我会修改需要的部分!
      猜你喜欢
      • 2021-08-07
      • 2012-10-18
      • 2022-11-02
      • 1970-01-01
      • 1970-01-01
      • 2014-10-17
      • 2021-11-25
      • 2014-09-07
      • 2016-11-02
      相关资源
      最近更新 更多