python中的pep_Python 3.7 中的 PEP 562

按照Python3.7的发布时间表,明天Python 3.7.0就发布了,最近各大开源项目都在做3.7相关的调整,之后我还会写文章更详细的介绍Python 3.7都带来了什么,敬请关注!Python 3.7是一个比较中庸的版本,我比较关注的是PEP 557 和 本文要提到的 PEP 562。

PEP557是Data Classes,之前我已经在 attrs 和 Python3.7 的 dataclasses里面专门介绍了。

PEP 562主要做的是什么呢?

Customization of Access to Module Attributes

就是能在模块下定义__getattr__和__dir__方法,实现定制访问模块属性了。有什么用呢?其实官网已经给出了答案:

弃用某些属性/函数

懒加载(lazy loading)

__getattr__让模块属性的访问非常灵活,我分别举几个例子:

弃用某些属性/函数时

有时候会修改一些函数或者属性,会写新的版本,旧版本的在一段时间之后会弃用。在大型项目中调用者有很多,不了解业务挨处修改成本很高,通常会在旧版本的函数中加入DeprecationWarning,有3个问题:

使用新的属性是没法提示DeprecationWarning,只能在模块级别加warn

如果找不到属性/函数直接抛错误了,不能做特殊处理

模块下弃用的函数多了,只能在每个函数内部加入warn,再执行新函数逻辑

而Python 3.7就没这个问题了:

# lib.py

import warnings

warnings.filterwarnings('default')  # Python 3.2开始默认会隐藏DeprecationWarning

def new_function(arg, other):

print('plz use me!')

_deprecated_map = {

'old_function': new_function

}

def __getattr__(name):

if name in _deprecated_map:

switch_to = _deprecated_map[name]

warnings.warn(f'{name} is deprecated. Switch to {__name__}.{switch_to.__name__}.',

DeprecationWarning)

return switch_to

raise AttributeError(f"module {__name__} has no attribute {name}")

看一下效果吧:

>>> from lib import old_function

/Users/dongwm/test/lib.py:18: DeprecationWarning: old_function is deprecated. Switch to lib.new_function.

DeprecationWarning)

>>> old_function

>>> old_function(1, 2)

plz use me!

懒加载

懒加载是指从一个数据对象通过方法获得里面的一个属性对象时,这个对应对象实际并没有随其父数据对象创建时一起保存在运行空间中,而是在其读取方法第一次被调用时才从其他数据源中加载到运行空间中,这样可以避免过早地导入过大的数据对象但并没有使用的空间占用浪费。

简单地说,按需才加载。这是一种设计模式。

Python3.7之前想要import模块成功,就得在模块里面把相关属性/函数/类等都准备好,其实import模块时候是很重的,现在可以通过PEP 562,能够极大的提升import的效率,尤其是导入了很重的逻辑。就如PEP中提的例子:

# lib/__init__.py

import importlib

__all__ = ['submod', ...]

def __getattr__(name):

if name in __all__:

return importlib.import_module("." + name, __name__)

raise AttributeError(f"module {__name__!r} has no attribute {name!r}")

# lib/submod.py

print("Submodule loaded")

class HeavyClass:

...

# main.py

import lib

lib.submodule.HeavyClass  # prints "Submodule loaded"

可以看到,import lib的时候,HeavyClass还没有没有加载的,当第一次使用lib.submodule的时候才会加载。

在标准库里面也有应用,比如 bpo-32596 中对 concurrent.futures 模块的修改:

def __dir__():

return __all__ + ('__author__', '__doc__')

def __getattr__(name):

global ProcessPoolExecutor, ThreadPoolExecutor

if name == 'ProcessPoolExecutor':

from .process import ProcessPoolExecutor as pe

ProcessPoolExecutor = pe

return pe

if name == 'ThreadPoolExecutor':

from .thread import ThreadPoolExecutor as te

ThreadPoolExecutor = te

return te

raise AttributeError(f"module {__name__} has no attribute {name}")

这样还可以让import asyncio时可以快15%。

标签: Python

顶一下

(0)

0%

踩一下

(0)

0%

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值