更好地说明闭包?

发布于 2024-08-31 16:00:22 字数 486 浏览 3 评论 0原文

我正在使用Dive Into Python 3一书学习Python。我喜欢它,但我不明白用于介绍闭包的示例 第 6.5 节。

我的意思是,我知道它是如何工作的,而且我认为它真的很酷。但我没有看到任何真正的好处:在我看来,只需在循环中逐行读取规则文件,并对读取的每一行进行搜索/替换,就可以实现相同的结果。

有人可以帮助我:

  • 理解为什么在这个例子中使用闭包可以改进代码(例如,更容易维护、扩展、重用或调试?)

  • 或者建议一些其他现实生活中的代码示例的来源,其中闭包真正发挥作用?

I am learning Python using Dive Into Python 3 book. I like it, but I don't understand the example used to introduce Closures in Section 6.5.

I mean, I see how it works, and I think it's really cool. But I don't see any real benefit: it seems to me the same result could be achieved by simply reading in the rules file line by line in a loop, and doing search / replace for each line read.

Could someone help me to:

  • either understand why using closures in this example improves the code (e.g., easier to maintain, extend, reuse, or debug?)

  • or suggest a source of some other real-life code examples where closures really shine?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

吃素的狼 2024-09-07 16:00:22

装饰器是闭包的一个例子。例如,

def decorate(f):
    def wrapped_function():
        print("Function is being called")
        f()
        print("Function call is finished")
    return wrapped_function

@decorate
def my_function():
    print("Hello world")

my_function()

函数 wrapped_function 是一个闭包,因为它保留对其作用域内的变量的访问,特别是参数 f,即原始函数。闭包允许您访问它。

闭包还允许您在函数调用之间保留状态,而不必求助于类:

def make_counter():
    next_value = 0
    def return_next_value():
        nonlocal next_value
        val = next_value
        next_value += 1
        return val
    return return_next_value

my_first_counter = make_counter()
my_second_counter = make_counter()
print(my_first_counter())
print(my_second_counter())
print(my_first_counter())
print(my_second_counter())
print(my_first_counter())
print(my_second_counter())

此外,绑定方法在技术上是闭包(尽管它们的实现方式可能不同)。绑定方法是类成员函数,其类内置于其中:

import sys
w = sys.stdout.write
w("Hello\n")

w 本质上是一个引用 sys.stdout 对象的闭包。

最后,我还没有读过那本书,但是快速阅读了您链接的章节,我对此非常不以为然——它是如此可怕的迂回,以至于它作为对闭包的解释毫无用处。

Decorators are an example of closures. For example,

def decorate(f):
    def wrapped_function():
        print("Function is being called")
        f()
        print("Function call is finished")
    return wrapped_function

@decorate
def my_function():
    print("Hello world")

my_function()

The function wrapped_function is a closure, because it retains access to the variables in its scope--in particular, the parameter f, the original function. Closures are what allow you to access it.

Closures also allow you to retain state across calls of a function, without having to resort to a class:

def make_counter():
    next_value = 0
    def return_next_value():
        nonlocal next_value
        val = next_value
        next_value += 1
        return val
    return return_next_value

my_first_counter = make_counter()
my_second_counter = make_counter()
print(my_first_counter())
print(my_second_counter())
print(my_first_counter())
print(my_second_counter())
print(my_first_counter())
print(my_second_counter())

Also, bound methods are technically closures (though they're probably implemented differently). Bound methods are class member functions with their class baked in:

import sys
w = sys.stdout.write
w("Hello\n")

w is essentially a closure with a reference to the sys.stdout object.

Finally, I haven't read that book, but a quick read of the chapter you linked and I'm very unimpressed--it's so horribly roundabout that it's useless as an explanation of closures.

入画浅相思 2024-09-07 16:00:22

当您可以访问整个代码库或没有考虑到可重用性时,这可能看起来不是特别有用,但是当尝试将逻辑分离为不同的可重用模块(可以通过以下方式并行实现)时,它非常强大和有用:不同的开发商。如果您只是从文件中读取模式字符串,则每个模块都必须了解该文件并传递烦人的模式字符串列表。如果您更改了系统,使模式字符串来自 URL 而不是文件,则可能会完全破坏您的整个代码库。另一方面,如果您的处理逻辑仅采用一个回调函数或多个回调函数,然后您有另一个使用文件中的内容动态构造函数的模块,则只需更改构造函数的组件。这就是能够动态创建函数的力量。

This might not seem particularly useful when you have access to the entire code base or when you do not have reusability in mind, but it is incredibly powerful and useful when trying to separate out logic into different, reusable modules that can be implemented in parallel by different developers. If you were to simply read the pattern strings from the file, every single module would have to be aware of this file and pass around that annoying list of pattern strings. And if you changed your system so that the pattern strings came from a URL instead of from a file, it could completely break your entire codebase. On the other hand, if you processing logic simply takes a callback function or several call back functions, and then you have another module that constructs the functions dynamically using content from a file, then only the component that constructs the functions needs to change. That is the power of being able to create functions dynamically.

七七 2024-09-07 16:00:22

这是 get configures 的闭包用法:

def confmaker():
   cf=ini_conf()
   def clo(*args):
      return cf.get(*args)
   return clo

cfget=confmaker()

cfget(...)

这里 ini_conf 仅被调用一次。在我的理解中,闭包避免了全局变量(如 cf),并使使用变得简单。

here's an closure usage, of get configures:

def confmaker():
   cf=ini_conf()
   def clo(*args):
      return cf.get(*args)
   return clo

cfget=confmaker()

cfget(...)

here ini_conf is called only once. In my understanding, closures avoid global variables(like cf), and make usage simple.

夜访吸血鬼 2024-09-07 16:00:22

尼尔斯-博姆写道(经过编辑):

只需在循环中逐行读取规则文件,并对读取的每一行进行搜索/替换,即可实现相同的结果。

事实上,这就是第 6.5 节中基本上完成的工作,其中规则放置在文件plural4-rules.txt 中。现在,规则作为字符串,可以在文件中维护,并且我们的代码将数据与控制分开。这使得项目更易于管理和维护。

尼尔斯的问题促使我勾勒出第六章的发展历程,以便准确理解作者试图证明的内容。在所提供的开发中,有很多值得学习的经验教训,它不仅涉及闭包,还涉及编码的最佳实践。

这个练习帮助我理解了如何使用生成器来替换替代的、不太抽象的、更复杂的实现。材料从 6.2 到 6.6 的发展过程具有足够的教育意义,可以在此概述。

因此,我从 Niels 的第二点开始,即 6.3 中将规则分解为单独的函数,作为草图的延续:

为什么在此示例中使用闭包可以改进代码?

作者此时指出:

添加这种抽象级别值得吗?嗯,还没有。

仍有第 6.4-6.6 节需要完成。闭包的故事,以及在本例中,构建复数生成器是逐步实现的,从名为plural(noun)的模块中的硬编码规则开始。因此,从第一个相关部分开始,总结我们到本章结束的方式,我们有以下内容。

6.2 让我们使用正则表达式:在这里,作者利用在初始复数函数中硬编码的复数规则来加强和扩展我们对正则表达式的理解。

6.3.函数列表:将复数函数中硬编码的规则抽象为多个独立函数。这是下一节的“垫脚石”。但它也表明 match_sxz() 和 match_sxz 的用法之间存在重要区别。

6.4 模式列表:我们在 6.3 中创建了单独的命名函数(配对为 match 和 apply)这一事实是多余的。这些函数都基于相同的模式,并且从不直接调用。这里他修改了这段代码,以便更简单地更改规则。这成为更进一步的抽象级别,规则现在被指定为称为模式的变量中的字符串。复数规则不再是函数。

6.5 模式文件:由于不再有重复代码和字符串列表中定义的复数规则,构建生成器的下一步是将这些字符串放入单独的文件中。在这里,它们变得更易于维护,与使用它们的代码分开。

6.6 生成器:生成器是一个通用的plural()函数,它解析规则文件,检查匹配,应用规则(如果适用),然后转到下一个规则。这是一个闭包的例子。

这就是plural()函数必须做的所有事情,这就是plural()函数应该做的所有事情。

这是一个相对简单而美观的开发,足够复杂,有用,并且可以扩展到人们可能发现的其他类型的问题,尤其是在文本模式识别方面。

作者在教程的最后解决了这个特定解决方案的性能问题。打开和读取文件中的行会降低性能,尤其是随着 open() 调用次数的增加。他指出,使用迭代器可以获得更好的性能,这将在本书的后面部分进行讨论。

Niels-Bom writes (with edits):

The same result could be achieved by simply reading in the rules file line by line in a loop, and doing search / replace for each line read.

And, in fact, this is what is essentially accomplished in section 6.5 where the rules are placed within the file plural4-rules.txt. With rules now as strings they can be maintained within a file, and our code separates data from control. This makes the project easier to manage and maintain.

Niels' question motivated me to sketch out the development of chapter 6 in an effort to understand exactly what the author was trying to demonstrate. There are many lessons to learn in the development provided and it is not just about closures, but about best practices in coding as well.

The exercise helped me understand how generators can be used to replace alternative, less abstract, and more enmeshed implementations. The development of the material from 6.2 through 6.6 is educational enough to sketch out here.

So I begin with Niels' second point concerning the breaking up of the rules into separate functions in 6.3 as a segue into the sketch:

Why does using closures in this example improve the code?

The author states at this point:

Was adding this level of abstraction worth it? Well, not yet.

There is still sections 6.4-6.6 to work through. The story of closures, and in this case, building a pluralization generator is achieved step by step, beginning with the hard coded rules in a module called plural(noun). So, beginning with the first relevant section and summarizing our way through to end of the chapter we have the following.

6.2 Let's Use Regular Expressions: Here the author takes the opportunity to reinforce and extend our understanding of regular expressions with pluralization rules hard coded within the initial plural function.

6.3. A List of Functions: Abstracts the rules hard coded within the plural function to several stand alone functions. This is a "stepping stone" to the next section. But it also demonstrates that there is an important difference between the usage of match_sxz() and match_sxz.

6.4 A List Of Patterns: The fact that we created individual named functions, paired as match and apply, in 6.3 are redundant. These functions are all based on the same pattern and are never called directly. Here he modifies this code to make it simpler to change the rules. This becomes a further level of abstraction, with the rules now specified as strings within the variable called pattern. The pluralization rules are no longer functions.

6.5 A File Of Patterns: With no more duplicate code and the pluralization rules defined in a list of strings, the next step toward building the generator is to put these strings in a separate file. Here they become more maintainable, separated from the code that uses them.

6.6 Generators: The generator is a generic plural() function that parses the rules file, checks for a match, applies the rule if appropriate, and goes to next rule. This is an example of a closure.

That’s all the plural() function has to do, and that’s all the plural() function should do.

A relatively simple and beautiful development, sophisticated enough to be useful, and extensible to other types of problems one might find, especially in text pattern recognition.

The author addresses performance concerns of this particular solution at the end of the tutorial. Opening and reading lines from a file will degrade performance, especially with an increasing number of open() calls. He states that better performance can be attained using an iterator, which is considered later in the book.

︶葆Ⅱㄣ 2024-09-07 16:00:22

循环逐行读取规则文件

逐行循环

循环

将推动整个楼层的性能。阅读一次,多次应用。

reading in the rules file line by line in a loop

line by line in a loop

loop

This will drive performance through the floor. Read once, apply many times.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文