静态变量模拟:类与生成器

1 投票
4 回答
1169 浏览
提问于 2025-04-17 04:25

我对在Python中使用静态变量感到好奇,结果找到了这个链接:为什么Python没有静态变量?

在我觉得很有用的一个被接受的回答中提到:“如果你希望函数每次被调用时行为都不同,你需要的是一个生成器。”

不过我有点困惑,因为那里的例子其实也可以用类来实现:

class Foo(object):                                                              
    def __init__(self, bar):                                                    
        self.bar = bar                                                          

    def __call__(self):                                                         
        self.bar = self.bar * 3 % 5                                             
        return self.bar

foo = Foo(bar)                                                                  
print foo()                                                                     
print foo()

这对我来说更有意义(但可能只是因为我之前没有好好使用过生成器)。

所以我的问题是,当函数每次需要改变行为时,使用生成器相比于类还有其他好处吗?

4 个回答

2

一个合适的生成器类看起来是这样的:

class Foo(object):                                                              
    def __init__(self, bar):                                                    
        self.bar = bar                                                          

    def __iter__(self):
        return self

    def next(self):
        self.bar = self.bar * 3 % 5                                             
        return self.bar

foo = Foo(3)                                                                  
print next(foo)                                                                     
print next(foo)

相应的生成器函数只需要一半的代码:

def Foo(bar):
    while True:
        bar = bar * 3 % 5   
        yield bar                                                          

foo = Foo(3)                                                                  
print next(foo)                                                                     
print next(foo)

生成器函数其实就是一种简化写法,用来处理最常见的循环方式。当你需要更复杂的功能时,使用类会更合适。

2

用生成器能做的事情,类也能做到。

使用生成器的原因很简单,就是它们写起来更简洁,而且在很多情况下比类更容易理解。当然,这也要看你具体在做什么。在你举的例子中,你只是想重复执行相同的操作并输出数字,所以用生成器非常合适。如果情况更复杂一些,那就应该用类。

3

生成器(这里说的简单生成器,不涉及协程)有一个非常明确的目的:编写迭代器。为了实现这个目的,你可以隐式地捕获局部变量,并使用一个关键字来暂停执行(而不是“终止”——你可以继续执行),然后给调用者返回迭代器的下一个值。使用生成器的好处有:

  • 逻辑更自然,因为你不需要把代码拆分成多个方法调用——所有的状态都被保留,包括程序计数器——你可以在生成值的过程中使用控制流。你可以把 yield x 替换成 results.append(x),然后在最后用 return results,这样就能得到一个和 list(the_original_generator(...)) 等价的函数。
  • 你不需要通过放入 self 来显式地让值保持长久——这样打字更少,阅读起来也更轻松。
  • 你不需要写一个类声明和两个方法声明(这些都是一些额外的代码,在Python中算是比较麻烦的)。

可以 利用“捕获局部变量”的特性来实现一个可迭代对象,虽然这样你可以有多个这样的对象,并且你使用的是迭代器(比如用 next_val = next(vals) 而不是 next_val = vals())。是否合适就要看具体情况了。

撰写回答