Python 嵌套 class 混乱

Python nested class confusion

正在研究惰性求值的思想。这是 Stream class 我遇到的问题:refer to 4.2.6 Stream

class Stream:
  """A lazily computed linked list.""" 

  class Empty:
      def __repr__(self):
          return 'Stream.empty'
  empty = Empty()

  def __init__(self, first, compute_rest= lambda: empty):
      assert callable(compute_rest), 'compute_rest must be callable.'
      self.first = first
      self._compute_rest = compute_rest

  @property
  def rest(self):
      """Return the rest of the stream, computing it if necessary."""
      if self._compute_rest is not None:
          self._rest = self._compute_rest()
          self._compute_rest = None
      return self._rest

  def __repr__(self):
      return 'Stream({0}, <...>)'.format(repr(self.first))

然后我制作了一个玩具Stream用于测试:

s = Stream(1, lambda: Stream(2+3, lambda: Stream(9)))

我想知道当我到达 Stream 结尾时会发生什么,所以我这样做:

s.rest.rest.rest

我期望屏幕打印出 Stream.empty,因为最后一个元素是 lambda: empty,但我收到错误回溯消息:

NameError                                 Traceback (most recent call last)
<ipython-input-6-64cf45661094> in <module>()
----> 1 s.rest.rest.rest

<ipython-input-4-7cc49730db55> in rest(self)
     16         """Return the rest of the stream, computing it if necessary."""
     17         if self._compute_rest is not None:
---> 18             self._rest = self._compute_rest()
     19             self._compute_rest = None
     20         return self._rest

<ipython-input-4-7cc49730db55> in <lambda>()
      7     empty = Empty()
      8 
----> 9     def __init__(self, first, compute_rest= lambda: empty):
     10         assert callable(compute_rest), 'compute_rest must be callable.'
     11         self.first = first

NameError: name 'empty' is not defined

所以我的问题是,我确实将 empty 定义为 class 变量,但解释器说它没有定义。如果我将 Empty class 定义从嵌套 class 中取出到全局框架,代码就可以工作。

我明白嵌套 class 是怎么出错的吗? 任何人都请给我一个提示。感谢您的宝贵时间。

post 中的代码无效且损坏。 lambda 将在父作用域中查找名称 empty。这里的问题是 class 主体 不是可嵌套范围的范围 ,因此只有全局范围保留用于查找。

来自Execution Model documentation

The scope of names defined in a class block is limited to the class block; it does not extend to the code blocks of methods

lambda 不是方法而是作为方法参数的默认值的可调用绑定在这里无关紧要。

您可以使用 class 名称来引用它:

def __init__(self, first, compute_rest= lambda: Stream.empty):

因为 Stream 现在是全局的(由 运行 和 class 语句设置)。