专栏首页IT派Python3.7中一种懒加载的方式

Python3.7中一种懒加载的方式

注意:这篇博文中的代码,现在已经是PyPI上modutil模块的一部分了。

Python3.7在模块上也添加了__getattr__()和__dir__()两个方法。这个新特性让我们能够实现一些有趣的事情。例如,通过定义__dir__方法,你可以要求dir(模块)只显示__all__中定义的内容了。

但对于我来说,我更关心__getattr__方法,以及我如何能利用这个特性实现懒加载。在本文的开始,我希望先告诉大家,大多数人的代码是不需要懒加载的。只有当懒加载带来的好处很有用时你才应该使用它,比如,一个运行时间很短的终端程序。对于大多数人,懒加载都是没有必要的,甚至是有害的,它会让你延后得知导入失败,而不是项目一启动时就能够知道。

旧方法

之前我们有两种方式做懒加载。最古老的方式是在局部加载,而不是全局加载(例如在你定义的函数内进行导入,而不是在模块顶部进行导入)。这种方式确实推迟了加载的时间点,在你的函数被运行时,函数里的import语句才会进行真正的加载。但它有一个缺点就是,这个import语句需要在不同的函数中写很多次。而且由于你只是在一些函数中写了import语句,你很可能写着写着就忘记了想要规避哪个模块的全局引用,然后后面又不小心全局引用了同样的模块。这个做法确实能实现懒加载,就是写法不够好。

另一种方法是使用importlib中提供的延迟加载器。Google、Facebook和Mercurial的很多开发者在使用这个延迟加载器。Google和Facebook主要是看中这个方法性能不错,Mercurial主要是看中这个方法比较简单、开发迅速。使用这个延迟加载器有一个很好的效果,它会提前检查要导入的模块是否能找到,如果找不到会抛出一个ModuleNotFoundError错误,而真正被延迟的只是模块加载的过程。

很多人很喜欢这个延迟加载器,以至于他们让所有的东西都延迟加载了。这样做有优点也有缺点。优点是你没有额外付出什么努力,就让所有的模块都延迟加载了。缺点是因为你让模块默认延迟加载了,会导致一些需要即时加载的模块的逻辑发生错误(这也就是Python箴言中为什么说明确优于隐晦)。事实上,Mercurial为了避免这个问题,专门维护了一个模块黑名单,黑名单上的模块不进行延迟加载。但为此,他们不得不一直维护这个名单,所以这样做也不是一个很好的办法。

新方法

在Python3.7中,模块上可以定义一个__getattr__方法,这让开发者可以定义一个函数,使得访问的模块属性不存在时,导入一个模块作为当前模块的属性。这样做确实也有“发现导入错误被推迟”这个弊病,但是由于你的导入还是全局的,所以代码更容易控制。

这个代码本身并不复杂。

你可以这样使用上面的代码

设计这个函数时,最棘手的部分就是模拟import ... as ... 语法来避免命名冲突,我最终选择使用一个类似原有as语法的字符串。我也可以把as语法字符串再拆分为第三个参数,这个参数也是一个字典对象,但是我想没必要这样做,能与原有语法有更多的相同点,当然是最好的。

无论如何,这个思考的过程都让我很享受。我喜欢这种用20行Python代码就完成一个不错的功能的感觉!

本文分享自微信公众号 - IT派(transfer_3255716726)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-04-28

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 高级工程师的晋升之路:如何用 JavaScript 打造十亿级的应用

    我以前开发过超大规模的JavaScript应用。现在我不做了,所以我觉得应该回顾下我学到的东西。昨天我在宴会上喝啤酒时有人问我,“嗨Malte,你为什么要来讲这...

    IT派
  • 程序员分析了 50 万条拼多多商品数据,告诉你到底是消费升级还是降级!

    我在杭州有位朋友,提到有家做社交的电商很火,叫拼多多,我没有在意,直到有一天,我居然在电视上看到了它的广告,广告画面活蹦乱跳,余音绕梁,我惊呆了,想知道这是何方...

    IT派
  • 语音助手经过6年发展,未来或将取代智能手机?

    IT派 - {技术青年圈} 持续关注互联网、区块链、人工智能领域 自2011年苹果在发布iPhone4s时,同场发布苹果系统级语音助手siri, 语音助手甚...

    IT派
  • 日志那点事儿——slf4j源码剖析

    前言: 说到日志,大多人都没空去研究,顶多知道用logger.info或者warn打打消息。那么commons-logging,slf4j,logback...

    用户1154259
  • 鱼和熊掌我都要之 Render-as-You-Fetch 模式

    感谢支持ayqy个人订阅号,每周义务推送1篇(only unique one)原创精品博文,话题包括但不限于前端、Node、Android、数学...

    ayqy贾杰
  • 面试必备——关于Java ClassLoader你真的了解吗

    类加载机制作为一个高频的面试题经常会在面试中被问到,前几天一个电话面试就问到,之前有了解过,但是没有梳理成自己的体系,所以说的有点凌乱,今天花点时间整理一下,分...

    苏先生
  • 【JVM系统学习之路】一篇看懂类加载

    嗨喽,小伙伴大家好,我是小春哥,今天是打卡 【JVM系统学习之路】 的第二篇文章 类加载子系统 ,在学习本章节首先回顾 上一章节【JVM系统学习之路】JVM与J...

    山间木匠
  • Java类加载机制

    答:当某个类加载器在接到加载类的请求时,会将加载任务委托给父类加载器,依次递归,父类加载器可以完成类加载任务,就成功返回;不能加载则子类加载器自己完成加载。有3...

    宇宙之一粟
  • Java 类加载机制及双亲委派模型

    即 加载 → \rightar...

    Steve Wang
  • JVM学习第三天(JVM的执行子系统)之类加载机制补充

    对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在Java虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间。这句话可以表达得更通俗一些...

    彼岸舞

扫码关注云+社区

领取腾讯云代金券