Function that returns an accumulator in Python
我读的是黑客和画家,我对作者提到的一个问题感到困惑,这个问题是为了说明不同编程语言的威力。
问题是:
We want to write a function that generates accumulators—a function that takes a number n, and returns a function that takes another number i and returns n incremented by i. (That’s incremented by, not plus. An accumulator has to accumulate.)
作者提到了几种不同编程语言的解决方案。例如,公共lisp:
1 2 | (defun foo (n) (lambda (i) (incf n i))) |
和JavaScript:
1 | function foo(n) { return function (i) { return n += i } } |
但是,当涉及到python时,以下代码不起作用:
1 2 3 4 5 6 7 8 9 | def foo(n): s = n def bar(i): s += i return s return bar f = foo(0) f(1) # UnboundLocalError: local variable 's' referenced before assignment |
一个简单的修改就能使它工作:
1 2 3 4 5 6 | def foo(n): s = [n] def bar(i): s[0] += i return s[0] return bar |
我是Python的新手。为什么第一个解决方案不起作用,而第二个解决方案起作用?作者提到了词汇变量,但我还是不明白。
这意味着您要为变量
在第二种情况下,
最后,更好的选择(在python 3中)是明确地告诉它
1 2 3 4 5 6 7 | def foo(n): s = n def bar(i): nonlocal s s += i return s return bar |
(实际上没有必要使用
*情况稍微复杂一些,但重要的问题是计算和分配是分两步执行的。
无限生成器是一种实现。可以在生成器实例上调用
1 2 3 4 5 6 7 8 9 10 | def incrementer(n, i): while True: n += i yield n g = incrementer(2, 5) print(g.__next__()) # 7 print(g.__next__()) # 12 print(g.__next__()) # 17 |
如果您需要一个灵活的增量器,一种可能是面向对象的方法:
1 2 3 4 5 6 7 8 9 10 11 12 | class Inc(object): def __init__(self, n=0): self.n = n def incrementer(self, i): self.n += i return self.n g = Inc(2) g.incrementer(5) # 7 g.incrementer(3) # 10 g.incrementer(7) # 17 |
以下内容有效:
1 2 3 4 5 6 | def foo(n): s = n def bar(i): s_ = s + i return s_ return bar |
内部函数
在另一个例子中,说
在python中,如果我们使用一个变量并将其传递给一个函数,那么无论您对该变量做什么更改,它都将按值调用,而不会反映到原始变量中。
但是,当使用列表而不是变量时,对函数列表所做的更改将反映在函数外部的原始列表中,因此称为引用调用。
这就是第二个选项起作用而第一个选项不起作用的原因。