2010-05-09 53 views
13

我正在使用Dive Into Python 3书学习Python。我喜欢它,但我不明白第6.5节中的example used to introduce ClosuresPython闭包示例代码

我的意思是,我看到它是如何工作的,我认为这是真的很酷。但是我没有看到任何真正的好处:在我看来,通过简单地在规则文件中逐行阅读循环,并为每行读取进行搜索/替换,可以实现相同的结果。

有人能帮助我:

  • 也不能理解,为什么在这个例子中使用闭包提高了代码(例如,更容易维护,扩展,再利用,或调试?)

  • 或建议一些其他真实代码示例的来源,其中闭包真正发光?

谢谢!

回答

21

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

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对象的引用的封闭件。

最后,我还没有读过那本书,而是快速阅读了关联的这一章,我对此非常无动于衷 - 它是如此可怕的迂回曲折,以至于它对闭包的解释没用。这里

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

cfget=confmaker() 

cfget(...) 

ini_conf只调用一次:

+0

谢谢! 我很喜欢使用类似风格和深度的这个答案的Python 3书,但我找不到一个... – max 2010-05-09 18:21:16

2

当您有权访问整个代码库或者您没有考虑到可重用性时,这可能看起来并不特别有用,但在尝试将逻辑分离成不同的可重用模块时,它非常强大和有用。由不同的开发人员并行执行。如果你只是从文件中读取模式字符串,每个模块都必须知道这个文件,并传递那些令人讨厌的模式字符串列表。如果您更改了系统,以使模式字符串来自URL而不是来自文件,那么它可能会彻底破坏整个代码库。另一方面,如果处理逻辑只是简单地使用回调函数或多个回调函数,然后又有另一个模块使用文件中的内容动态地构造函数,那么只有构造函数的组件需要更改。这是能够动态创建功能的力量。

+0

是;但为什么不传递字符串列表?一个模块将处理文件或URL或我们拥有的任何其他输入源。而程序的其余部分将采用实际的规则作为模式字符串列表。 – max 2010-05-09 18:37:11

+0

@ user336527,另一个模块可以简单地验证对象是否符合谓词列表。它甚至不需要知道这些谓词是什么。这简化了第二个模块的任务,并且允许重复使用与字符串匹配无关的谓词。虽然,我会同意,这个例子有点人为的做法。比这个例子有更好的用例。 – 2010-05-09 22:04:34

+0

谢谢,这让我对事情更加清楚! – max 2010-05-10 03:18:22

0

读取一行规则文件线环路由线

线在一个循环

这将通过地面驱动性能。阅读一次,多次应用。

+0

对不起,我不是很精确。当然,我会将从文件中读取的模式字符串存储在列表中,然后始终遍历该列表。但是如何传递一个函数列表比传递一个模式字符串列表更好? – max 2010-05-09 18:39:26

2

这里是一个封闭的使用,获取配置。在我的理解中,闭包避免了全局变量(如cf),并使用法简单。

1

尼尔斯-BOM写入(与编辑):

同样的结果可以通过线在规则文件中的行只是在读一环,和做搜索/替换为读取每一行来实现。

而事实上,这就是6.5节中的规则放在文件plural4-rules.txt中所实现的。现在将规则作为字符串保存在文件中,我们的代码将数据从控制中分离出来。这使项目更容易管理和维护。

尼尔斯的问题促使我勾画出第6章的发展,努力准确了解作者试图论证。在提供的开发中有很多要学习的经验教训,它不仅仅关于闭包,还包括编码方面的最佳实践。

的锻炼让我了解到发生器可以如何被用来取代替代,那么抽象,多落网实现。从6.2到6.6的材料的发展足够教育在这里草图。

为什么使用闭包在这个例子中提高代码:

所以我与尼尔斯关于分手的规则成单独的功能在6.3的赛格瑞进入草图第二点开始的?

笔者状态在这一点上:

新增这级别的抽象的价值呢?那么,还没有。

还有部分6.4-6.6工作通过。封闭的故事,在这种情况下,建立一个多元化的发电机是一步一步实现的,从一个称为复数(名词)的模块中的硬编码规则开始。因此,从第一个相关部分开始,总结本章的结尾部分,我们会得到以下结论。

6.2让我们使用正则表达式:这里笔者借此机会加强和扩大我们与最初的复数函数中硬编码的复数化规则的正则表达式的理解。

6.3。函数列表:将复数函数中硬编码的规则抽象为几个独立的函数。这是下一部分的“垫脚石”。但是它也证明了match_sxz()和match_sxz的用法有一个重要的区别。

6.4匹配模式列表:我们创造了个人命名的功能,如配对的匹配和应用,在6.3实际上是多余的。这些功能都基于相同的模式,并且不会直接调用。在这里他修改了这段代码,以便更改规则。这成为了进一步的抽象层次,规则现在在称为模式的变量中被指定为字符串。多元化规则不再是功能。

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

6.6生成器:生成器是一个通用的plural()函数,用于解析规则文件,检查匹配项,适用规则并转到下一条规则。这是关闭的一个例子。

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

一个相对简单和美观的开发,足够复杂,有用,可扩展到其他类型的问题,尤其是在文本模式识别中。

作者在本教程结束时讨论了这个特定解决方案的性能问题。从文件中打开和读取行会降低性能,尤其是在open()调用数量不断增加的情况下。他表示,使用迭代器可以获得更好的性能,本书后面将对此进行考虑。