PEP-0328 中文翻译 By Lance Van

最近在做微信公众平台的后台开发,找到了一个Python的微信SDKwechat-python-sdk,使用之后却发现不支持Python3,于是决定移植到Python3上面。

在移植的过程中,发现原来的代码在import不能正确导入同一package下的module,在网上搜寻方案无果,怒翻译Python官方的PEP 0328

感谢chickenjohn桑在翻译过程中给予的帮助。也希望各位多给予指导。

目录

摘要
Timeline
使用括号的原因
使用绝对导入的原因
使用相对导入的原因
Guido的选择
相对导入与__name__属性
相对导入与sys.modules中的间接寻址入口
参考资料
版权所有

摘要

import声明存在两个问题:

  • 过长的import声明很难写,可能为了符合Python编码规范出现很多换行。
  • 存在很多包的情况下,import操作可能存在语义含糊不清的情况;例如,在一个包中,import foo操作可能代表导入了包内的foo模块,也可能代表导入了包外的foo模块。(更准确的说,一个本地的模块或包可能直接切断了与外部(即sys.path)的联系。)

对于第一个问题,我们建议用括号将要导入的名称括起来,以满足Python的换行标准。对于第二个问题,我们建议所有的import默认以绝对路径的方式声明,并用特殊语法(即开头的.)表示相对路径。

Timeline

在Python 2.5中,加入以下语句可以应用新的绝对路径标准:

  __future__ import absolute_import

如此就能优雅的使用相对路径导入了。在Python 2.6中,任何出现包内导入的import操作都会引起DeprecationWarning(这对于没有使用相对导入语法的from <> import操作同样适用)。

使用括号的原因

现在,如果要从一个模块或包中导入很多名称时,你不得不从如下不够优雅的方式中做出选择:

  • 利用反斜杠分隔开:

    from Tkinter import Tk, Frame, Button, Entry, Canvas, Text, \\\\
    LEFT, DISABLED, NORMAL, RIDGE, END
    
  • 将一次import操作分为多次import

    from Tkinter import Tk, Frame, Button, Entry, Canvas, Text
    from Tkinter import LEFT, DISABLED, NORMAL, RIDGE, END
    

( 不讨论import *的情况 ;-)
作为替代,应使用Python标准的分组机制进行import操作:

  from Tkinter import (Tk, Frame, Button, Entry, Canvas, Text, 
  LEFT, DISABLED, NORMAL, RIDGE, END)

这个建议从提出开始就被BDFL审批。

Python 2.4版本开始引入这种括号的支持

使用绝对导入的原因

在Python 2.4和更早的版本中,

  import foo

这个语句可能指代一个库中的顶层模块,也可能指代另一个本地包中的模块。作为Python标准库的扩展,越来越多的包内模块无意中与Python标准库的同名模块产生了冲突。这个问题导致了很多时候无法确定它导入了哪一个模块,从而产生歧义。为了消除这个歧义,我们建议此种方式导入的foo必须是在sys.path中可以找到的模块或包。此方式的导入称为绝对导入。

Python-dev社区默认选用绝对导入的原因是这种方式在实际中更常用,而且能提供所有使用相对导入时可提供的功能,尽管这可能导致一系列麻烦:例如修改顶层包名称以及修改包目录结构。

因为这可能导致语义上的变动,在Python 2.5和2.6中,绝对导入不是必须遵守的,加入以下语句可以应用绝对引用标准:

  from __future__ import absolute_import

这个建议从提出开始就被BDFL审批。

使用相对导入的原因

与绝对导入相对的,是否允许相对导入的问题也出现了。示例如下,这些示例的重点在于如何规整大包的结构而不必在大包的子包中做改动。除此之外,不使用相对导入很难单独导入包内的一个模块。

Guido认可相对导入这种导入方式,但是相对导入在语法上可能产生很多歧义。有一个不成文的约定就是相对导入需要列出导入的的具体名称(就是说,形如import foo单独的导入被认为是绝对导入)。

不同的相对导入方式如下:

  • Guido的导入方式

    from .foo import bar
    

以及

  from ...foo import bar

这两种形式有很多不同的解释方式。 一种解释方式是一个.表示文件结构中的一个层级。这样的话有很多人抱怨,数.的个数很麻烦,显然不够优雅。另外一个选择是只允许一个文件层次之间的相对导入。这样又会造成很多功能上的丧失,还有很多人抱怨在这种表示下会忘记.。最终的方案是声明一种相对导入寻找包与模块的算法,而这又违反了“The Zen of Python”中的"Explicit is better than implicit"(外显胜于内隐)。(这个被提议的算法主要思想是“自下而上,直至触顶”)

有些人提出使用其他标点符号作为分隔符,比如“-”或者"^"。

有些人提出使用"*"

  from *.foo import bar
  • 还有一个选择是从很多包结构中导入:
    from pkg.pkg import

    from parent.parent import

很多人(包括Guido)认为这种方式看起来很丑,但是这种方式非常明确而且一目了然。 总之,更多人喜欢以__pkg__作为更短的选项。

  • 有人提出只允许同一文件层级之间的引用。 换句话说,用相对导入无法导入更高层级的模块,只能以如下方式导入:
    from .spam import eggs
    或者
    import .spam.eggs

  • 有的人喜欢索引的父目录表示方式
    from -2.spam import eggs
    这种方式下,从当前目录导入只需要如下方式:
    from .spam import eggs

  • 最后,当要导入的包处于比较深的文件结构时,一些人不愿意从import的写法改为from ... import。他们建议重写import的语法:
    from MODULE import NAMES as RENAME searching HOW
    或者
    import NAMES as RENAME from MODULE searching HOW
    [from NAMES] [in WHERE] import ...
    然而,这在Python 2.5中很可能不能实现(改动过大),允许相对导入非常关键,所以()除此之外,这个被建议的语法有很多问题:

  • 准确的语法是什么?(什么条件下应用)
  • searching字句应对应什么?也就是说,应该采用一下哪种方式:
    import foo as bar searching XXX, spam as ham searching XXX
    或者
    import foo as bar, spam as ham searching XXX

Guido的选择

Guido已经宣布[1]相对导入要在导入路径前面加一个.表示当前的包,两个或者更多的.表示在当前包的父包中进行相对导入操作,一个.表示一个层级。以下是一个包的样例:

  package/
     __init__.py
     subpackage1/
         __init__.py
         moduleX.py
         moduleY.py
      subpackage2/
          __init__.py
          moduleZ.py
      moduleA.py

假设所在的文件是moduleX.pysubpackage1/__init__.py, 新语法的正确用法如下:

  from .moduleY import spam
  from .moduleY import spam as ham
  from . import moduleY
  from ..subpackage1 import moduleY
  from ..subpackage2.moduleZ import eggs
  from ..moduleA import foo
  from ...package import bar
  from ...sys import path

注意,虽然最后一个例子中的用法是合法的,但是不推荐这样做。(Guido用疯狂(insane)这个词来形容这种做法)

相对导入必须使用形如from <> import的方式; 形如import <>的均视为绝对导入。当然,绝对导入也可以通过省略.的方式进行from <> import操作。 禁止使用import .foo的原因是:在

  import XXX.YYY.ZZZ

操作后,

  XXX.YYY.ZZZ

可以在表达式中使用,而

 .module

不能在表达式中使用。

相对导入与__name__属性

相对导入使用一个模块的__name__属性确定模块在包层次结构中的位置。如果模块的名字不包含任何包的信息(比如它被设置为__main__),相对导入就会以处理最顶层模块一样处理,无视这个模块的实际位置。

相对导入与sys.modules中的间接寻址入口

当包的概念被引出时,在sys.modules中间接寻址入口的概念应运而生[2]。当一个sys.module中一个包中的模块的入口的值是None的时候,它表示当前模块确实表示顶层。例如,'Sound.Effects.string'sys.modules的值可能是None。这意味着导入对应'Sound.Effects.string'的操作就是导入string模块。

这又引出了一个当绝对导入对应相对导入情况下的的优化方式。但是在PEP对于绝对导入和相对导入有着明确界定的情况下,这种优化方式就不再需要了。当绝对导入或相对导入成为了唯一可用的导入方式时,sys.modules中的间接寻址入口不再支持。

参考资料

了解更多相关背景可以参考以下主题:

版权所有

这个文档已被放置在公共域名。
来源:https://hg.python.org/peps/file/tip/pep-0328.txt

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,633评论 18 139
  • Python是一种对代码风格很重视的语言,从缩进就能看出这一点,Python强调易于理解。最近在负责代码重构的工作...
    知曰阅读 10,840评论 1 85
  • 前言 Python的创始人为Guido van Rossum。1989年圣诞节期间,在阿姆斯特丹,Guido为了打...
    依依玖玥阅读 3,565评论 6 37
  • 1.倾尽天下——河图 血染江山的画,怎敌你眉间 一点朱砂。覆了天下也罢,始终不过 一场繁华。碧血染就桃花,只想再见...
    爱上一匹野马阅读 972评论 0 0
  • hazel默认不处理子文件夹,要处理子文件夹,你必须分开建立两个规则。 要处理子文件夹必须先建立一个这样的规则 然...
    鸭梨山大哎阅读 844评论 0 0