Python 中如何实现 Golang 风格的闭包?

根据 Go by Example 里的 Closures 实现,想用 Python 实现一下, 没有成功

Golang

package main

import “fmt”

func intSeq() func() int { i := 0 return func() int { i += 1 return i } }

func main() { nextInt := intSeq()

fmt.Println(nextInt())
fmt.Println(nextInt())
fmt.Println(nextInt())
fmt.Println(nextInt())

// 一脸懵 为什么不重新初始化 intSeq(),值会一直添加???
newInts := intSeq()
fmt.Println(newInts())

}

输出

1
2
3
4
1

Python 2.7

# coding: utf-8

def intSeq(): def func(): i = 0 i += 1 return i return func

if name == “main”: nextInt = intSeq() print nextInt() print nextInt() print nextInt() print nextInt()

newInts = intSeq()
print nextInt()

输出结果:

1
1
1
1
1

话说 Python 中要怎么实现?


Python 中如何实现 Golang 风格的闭包?

更多关于Python 中如何实现 Golang 风格的闭包?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

17 回复

def seq():
…i = 0
…def func():
…i += 1
…return i
…return func

更多关于Python 中如何实现 Golang 风格的闭包?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Python里搞Golang风格的闭包,关键得理解变量捕获的差异。Golang的闭包捕获的是变量的引用,而Python默认捕获的是变量在闭包创建时的值。要实现类似Golang的行为,你得用可变容器来包装变量。

看这个例子,模拟Golang里常见的闭包模式:

def create_counter():
    # 用列表包装计数器,列表是可变对象
    count = [0]
    
    def counter():
        count[0] += 1
        return count[0]
    
    return counter

# 使用闭包
counter1 = create_counter()
print(counter1())  # 输出: 1
print(counter1())  # 输出: 2

counter2 = create_counter()
print(counter2())  # 输出: 1

更Pythonic的写法可以用nonlocal关键字(Python 3+):

def create_counter():
    count = 0
    
    def counter():
        nonlocal count  # 声明count不是局部变量
        count += 1
        return count
    
    return counter

对于需要在循环中创建闭包的情况,Golang风格的实现:

def create_funcs():
    funcs = []
    for i in range(3):
        # 用默认参数捕获当前值
        funcs.append(lambda x=i: x * 2)  # x=i 创建了参数默认值
    return funcs

funcs = create_funcs()
for f in funcs:
    print(f())  # 正确输出: 0, 2, 4

简单说就是用可变对象或nonlocal来模拟引用捕获。

def intSeq():
i = [0]
def func():
i[0] += 1
return i[0]
return func

if name == “main”:
nextInt = intSeq()
print nextInt()
print nextInt()
print nextInt()
print nextInt()

newInts = intSeq()
print nextInt()

UnboundLocalError: local variable ‘i’ referenced before assignment
输出结果不对
输出结果
<br>1<br>2<br>3<br>4<br>5<br>

一楼笔误,少贴了一行 nonlocal。

def seq():
…i = 0
…def func():
…nonlocal i
…i += 1
…return i
…return func

newInts = intSeq()
print nextInt()

to
nextInt = intSeq()
print nextInt()

Python 3 …


newInts = intSeq()
print nextInt()
–>
newInts = intSeq()
print newInts()
这样就行了

因为 Python 不需这么玩唉
Python 的哲学是不要自己造轮子。

>>> def g_factory():
i = 1
while True:
yield i
i += 1


>>> g = g_factory()
>>> next(g)
1
>>> next(g)
2
>>>

>>> from itertools import count
>>> c = count(1)
>>> next©
1
>>> next©
2
>>>

>>> from itertools import cycle
>>> c = cycle([1,2,3])
>>> next©
1
>>> next©
2
>>> next©
3
>>> next©
1
>>>

为什么大家这么爱好实现一个有状态的函数?
这需求不是应该用对象吗?

The key point is not how to implement a generator.


But sometimes its not worth create a class.
Use Closures is easy and convenient.

To implement a generator is must-know trick for pythoneer, the key point is 'how to solve the problem or fulfill the requirement. you are using Python, you should obey its philosophy. generator is better solution, if you just want better enclosure go lisp.

yield 吧… python generator

object 和 closure 分别是 OOP 和 FP 对同一需求的不同实现,只不过现在很多语言同时支持这两种罢了
first class function (或者,按 python 的说法,functions as first class objects )都是需要语言支持 closure 才能实现的

可是它表现为一个 function,而 function “应该是”无状态的,它的所有输入都应该被明确列出

回到顶部