ZetCode

Python 闭包

最后修改于 2024 年 1 月 29 日

Python 闭包教程展示了如何在 Python 中使用闭包函数。

Python 函数是一等公民。这意味着函数与 Python 中的其他对象具有相同的地位。函数可以赋值给变量、存储在集合中、动态创建和删除,或作为参数传递。

嵌套函数,也称为内部函数,是在另一个函数内部定义的函数。

nested_fun.py
#!/usr/bin/python

def main():

    def build_message(name):

        msg = f'Hello {name}'
        return msg

    name = input("Enter your name: ")
    msg = build_message(name)

    print(msg)


if __name__ == "__main__":
    main()

build_message 是一个嵌套函数。它在外部 main 函数内部定义和调用。

Python 闭包

闭包是一个嵌套函数,它可以访问来自已完成执行的封闭函数的自由变量。 Python 闭包的三个特征是

自由变量是在局部作用域中未绑定的变量。 为了使闭包能够使用不可变变量(例如数字和字符串),我们必须使用 nonlocal 关键字。

Python 闭包有助于避免使用全局值,并提供某种形式的数据隐藏。 它们用于 Python 装饰器中。

Python 简单闭包示例

以下是一个 Python 闭包的简单示例。

simple_closure.py
#!/usr/bin/python

def make_printer(msg):

    msg = "hi there"

    def printer():
        print(msg)

    return printer


myprinter = make_printer("Hello there")
myprinter()
myprinter()
myprinter()

在该示例中,我们有一个 make_printer 函数,该函数创建并返回一个函数。 嵌套的 printer 函数是闭包。

myprinter = make_printer("Hello there")

make_printer 函数返回一个 printer 函数并将其分配给 myprinter 变量。 此时,它已完成执行。 但是,printer 闭包仍然可以访问 msg 变量。

$ ./simple_closure.py
hi there
hi there
hi there

带 nonlocal 关键字的 Python 闭包

nonlocal 关键字允许我们修改外部函数范围中具有不可变类型的变量。

counter.py
#!/usr/bin/python

def make_counter():

    count = 0
    def inner():

        nonlocal count
        count += 1
        return count

    return inner


counter = make_counter()

c = counter()
print(c)

c = counter()
print(c)

c = counter()
print(c)

该示例创建了一个计数器函数。

def make_counter():

    count = 0
    def inner():

        nonlocal count
        count += 1
        return count

    return inner

通过使用 nonlocal 关键字,count 变量成为一个自由变量。 现在我们可以修改它。

$ ./counter.py
1
2
3

Python 闭包与类

Python 闭包可以是小型类的替代解决方案。

summer.py
#!/usr/bin/python

class Summer():

    def __init__(self):
        self.data = []

    def __call__(self, val):

        self.data.append(val)
        _sum = sum(self.data)

        return _sum

summer = Summer()

s = summer(1)
print(s)

s = summer(2)
print(s)

s = summer(3)
print(s)

s = summer(4)
print(s)

我们有一个 Summer 类,它对传递给对象的值求和。

def __init__(self):
    self.data = []

数据保存在对象属性中,并在构造函数中创建。

def __call__(self, val):

    self.data.append(val)
    _sum = sum(self.data)

    return _sum

每次调用该实例时,都会追加该值,并计算并返回总和。

以下是使用 Python 闭包的替代解决方案。

summer2.py
#!/usr/bin/python

def make_summer():

    data = []

    def summer(val):

        data.append(val)
        _sum = sum(data)

        return _sum

    return summer

summer = make_summer()

s = summer(1)
print(s)

s = summer(2)
print(s)

s = summer(3)
print(s)

s = summer(4)
print(s)

我们使用 Python 闭包具有相同的功能。

def make_summer():

    data = []

    def summer(val):

        data.append(val)
        _sum = sum(data)

        return _sum

    return summer

因为 data 是一个可变的列表,所以我们不必使用 nonlocal 关键字。

来源

Python 语言参考

在本文中,我们使用了 Python 闭包。

作者

我叫 Jan Bodnar,是一位充满热情的程序员,拥有丰富的编程经验。 自 2007 年以来,我一直在撰写编程文章。 迄今为止,我已经撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 Python 教程