我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Python闭包技巧介绍

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Python闭包技巧介绍

1.闭包:用函数代替类

有时我们会定义只有一个方法(除了__init__()之外)的类,而这种类可以通过使用闭包(closure)来替代。闭包是被外层函数包围的内层函数,它能够获取外层函数范围中的变量(即使外层函数已执行完毕)。因此闭包可以保存额外的变量环境,用于在函数调用时使用。考虑下面这个例子,这个类允许用户通过某种模板方案来获取URL。


from urllib.request import urlopen
class UrlTemplate:
     def __init__(self, template) -> None:
         self.template = template
     def open(self, **kwargs):
         return urlopen(self.template.format_map(kwargs))
    
 yahoo = UrlTemplate('http://finance.yahoo.com/d/quotes.csv?s={names}&f={fields}')
 for line in yahoo.open(names='IBM,AAPL,FB', fields = 'sllclv'):
     print(line.decode('utf-8'))


这个类可以用一个简单的函数来替代:


def urltempalte(template):
    # 后面用对象再次调用函数的时候传入kwargs
    def opener(**kwargs):
        return urlopen(template.format_map(kwargs))
    return opener

yahoo = urltempalte('http://finance.yahoo.com/d/quotes.csv?s={names}&f={fields}')
for line in yahoo(names='IBM,AAPL,FB', fields = 'sllclv'):
    print(line.decode('utf-8'))


在许多情况下,我们会使用只有单个方法的类的原因是需要保存额外的状态给类方法使用。我们上面提到的UrlTemplate类的唯一目的就是将template的值保存在某处,然后在open()方法中使用它。而使用闭包来解决该问题会更加简短和优雅,我们使用opener()函数记住参数template的值,然后再随后的调用中使用该值。
所以大家在编写代码中需要附加额外的状态给函数时,一定要考虑使用闭包。

2.访问定义在闭包的内的变量

我们知道闭包内层可以用来存储函数需要用到的变量环境。接下来,我们可以通过函数来扩展闭包,使得在闭包内层定义的变量可以被访问和修改。
一般来说,闭包内层定义的变量对外界来说是完全隔离的,如果想要访问和修改它们,需要编写存取函数(accessor function, 即getter/setter方法),并将它们做为函数属性附加到闭包上来提供对内层变量的访问支持:


def sample():
    n = 0
    # 闭包函数
    def func():
        print("n =", n)
    
    # 存取函数(accessor function),即getter/setter方法
    def get_n():
        return n

    def set_n(value):
        # 必须要加nolocal才能修改内层变量
        nonlocal n
        n = value

    # 做为函数属性附加
    func.get_n = get_n
    func.set_n = set_n
    return func

该算法测试运行结果如下:


f = sample()
f() # n = 0
f.set_n(10)
f() # n = 10
print(f.get_n()) # 10


可以看到,get_n()set_n()工作起来很像实例的方法。注意一定要将get_n()和set_n()做为函数属性附加上去,否则在调用set_n()get_n()就会报错:'function' object has no attribute 'set_n'
如果我们希望让闭包完全模拟成类实例,我们需要架构内层函数拷贝到一个实例的字典中然后将它返回。

示例如下:


import sys
class ClosureInstance:
    def __init__(self, locals=None) -> None:
        if locals is None:
            locals = sys._getframe(1).f_locals 
            
        # Update instance dictionary with callables
        self.__dict__.update(
            (key, value) for key, value in locals.items() if callable(value)
        )

    # Redirect special methods
    def __len__(self):
        return self.__dict__['__len__']()
    
# Example use
def Stack():
    items = []

    def push(item):
        items.append(item)
    
    def pop():
        return items.pop()
    
    def __len__():
        return len(items)
    
    return ClosureInstance()

下面展示了对应的测试结果:


s = Stack()
print(s) # <__main__.ClosureInstance object at 0x101efc280>
s.push(10)
s.push(20)
s.push('Hello')
print(len(s)) # 3
print(s.pop()) # Hello
print(s.pop()) # 20
print(s.pop()) # 10


用闭包模型类的功能比传统的类实现方法要快一些。比如我们用下面这个类做为测试对比。


class Stack2:
    def __init__(self) -> None:
        self.items = []
    
    def push(self, item):
        self.items.append(item)

    def pop(self):
        return self.items.pop()
    
    def __len__(self):
        return len(self.items)

下面是我们的测试结果:


from timeit import timeit
s = Stack()
print(timeit('s.push(1);s.pop()', 'from __main__ import s'))
# 0.98746542
s = Stack2()
print(timeit('s.push(1);s.pop()', 'from __main__ import s'))
# 1.07070521


可以看到采用闭包的版本要快大约8%。因为对于实例而言,测试话费的大部分时间都在对实例变量的访问上,而闭包要更快一些,因为不用涉及额外的self变量。
不过这种奇技淫巧在代码中还是要谨慎使用,因为相比一个真正的类,这种方法其实是相当怪异的。像继承、属性、描述符或者类方法这样的特性在这种方法都是无法使用的。而且我们还需要一些花招才能让特殊方法正常工作(比如我们上面ClosureInstance中对__len__()的实现)。不过,这仍然是一个非常有学术价值的例子,它告诉我们对闭包内部提供访问机制能够实现怎样的功能。

到此这篇关于Python闭包技巧介绍的文章就介绍到这了,更多相关Python闭包内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Python闭包技巧介绍

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Python闭包技巧是什么

这篇文章主要讲解了“Python闭包技巧是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Python闭包技巧是什么”吧!1.闭包:用函数代替类有时我们会定义只有一个方法(除了__init
2023-06-21

JavaScript闭包原理与使用介绍

闭包是js的一个难点也是它的一个特色,是我们必须掌握的js高级特性,下面这篇文章主要给大家介绍了关于JavaScript闭包函数的相关资料,需要的朋友可以参考下
2022-11-13

Windows 8技巧:Windows 8中FlipView的使用技巧介绍

FlipView控件类似于翻页控件,并且是现成的翻页按钮,你只需要为其增加数据项即可。本文讲述两种方式的FlipView项目和展示。一:直接前台FlipViewItem复制代码代码如下:
2022-06-04

优化Python中len函数的性能技巧介绍

了解Python中len函数的性能优化技巧,需要具体代码示例Python是一种简单易学的高级编程语言,被广泛应用于数据处理、科学计算、机器学习等领域。在Python中,len函数是一个常用的函数,用于获取容器(如列表、元组、字符串等)中的
优化Python中len函数的性能技巧介绍
2024-01-13

Wordpress被忽略的SEO技巧介绍

很多时候,我们做网站时在本身网站没有完全架构好就去寻找所谓的SEO技巧。这往往是本末倒置。就拿wordpress来说,本身的SEO优化已经做的非常好,甚至细节都帮我们考虑到了。而这些细节经常被我们忽略。本文将从一个小细节说起来提升你网站的S
2022-06-12

XP桌面文字技巧使用介绍

★其实还可以按住Alt键,然后在小键盘输入“0160”,这样也可以达到同样效果。 ★若找不到内码输入法,可右击输入法切换图标选择“设置”,再单击“添加”按钮从&ldqu
2023-06-01

电脑技巧:Microsoft Edge浏览器技巧介绍,值得收藏!

大家可以将其它浏览器的书签数据等数据很方便迁移到Edge浏览器,只需点击几下就可以导入书签、历史记录和密码。
电脑技巧:Microsoft Edge浏览器技巧介绍,值得收藏!
2024-04-23

Windows 7系统70个小技巧的介绍

1. 电脑守卫  我很少让其他人使用我的电脑,因为我怕他们会把它弄的乱七八糟的,但是看起来,微软已经替我考虑到这一点并且顺便解决了这个问题。PC Safeguard不会让任何人把你电脑的设置弄乱,因为当他们注销的时候,所有的设定都会恢复到正
2023-05-25

最实用Win7技巧快捷操作介绍

Win7的桌面设置更加个性化,我们的照片、喜欢的壁纸,都可以随时设为编程客栈背景,而女生们的桌面壁纸很多都比较卡哇伊,但如果去做演示时,投射到投影公示,也许就会带来一些尴尬。其实在演示前,我们只需要通过Win+X快捷键打开移动中心,对演示设
2023-05-26

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录