别院牧志知识库 别院牧志知识库
首页
  • 基础

    • 全栈之路
    • 😎Awesome资源
  • 进阶

    • Python 工匠系列
    • 高阶知识点
  • 指南教程

    • Socket 编程
    • 异步编程
    • PEP 系列
  • 面试

    • Python 面试题
    • 2022 面试记录
    • 2021 面试记录
    • 2020 面试记录
    • 2019 面试记录
    • 数据库索引原理
  • 基金

    • 基金知识
    • 基金经理
  • 细读经典

    • 德隆-三个知道
    • 孔曼子-摊大饼理论
    • 配置者说-躺赢之路
    • 资水-建立自己的投资体系
    • 反脆弱
  • Git 参考手册
  • 提问的智慧
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
首页
  • 基础

    • 全栈之路
    • 😎Awesome资源
  • 进阶

    • Python 工匠系列
    • 高阶知识点
  • 指南教程

    • Socket 编程
    • 异步编程
    • PEP 系列
  • 面试

    • Python 面试题
    • 2022 面试记录
    • 2021 面试记录
    • 2020 面试记录
    • 2019 面试记录
    • 数据库索引原理
  • 基金

    • 基金知识
    • 基金经理
  • 细读经典

    • 德隆-三个知道
    • 孔曼子-摊大饼理论
    • 配置者说-躺赢之路
    • 资水-建立自己的投资体系
    • 反脆弱
  • Git 参考手册
  • 提问的智慧
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 辨析

  • Sockets编程

  • Django

  • stackoverflow

  • Flask

  • 全栈之路

  • 面试

  • 代码片段

  • 异步编程

  • 😎Awesome资源

  • PEP

    • PEP 中文翻译计划
    • [译] PEP-8 -- 编码风格指南中文版✨✨
    • [译] PEP202--列表推导式
    • [译] PEP 255--简单的生成器
    • [译] PEP 285--添加一种布尔类型
    • [译] PEP 318--函数和方法的装饰器
    • [译] PEP 328--导入多行及绝对/相对
      • 摘要
      • Timeline
      • 使用括号的原因
      • 使用绝对导入的原因
      • 使用相对导入的原因
      • Guido 的选择
      • 相对导入与__name__属性
      • 相对导入与sys.modules中的间接寻址入口
      • 参考资料
      • 版权所有
    • [译]pep 333 -- Python Web 服务器网关接口 v1.0
    • [译]PEP 342--增强型生成器——协程
    • [译]PEP 380--子生成器的语法
    • [译]PEP 484 -- 类型提示
    • [译] PEP 525--异步生成器
    • [译] PEP 530--异步推导式
    • [译] PEP614--放宽对装饰器的语法限制
    • [译] PEP-312--Python 3.10 的首个 PEP 诞生,内置类型 zip() 迎来新特性
    • [译]PEP 3099--Python 3 中不会改变的事情
    • [译] PEP 3105--改 print 为函数
    • [译]PEP 3107 -- 函数注解
    • [译]PEP-3129 类装饰器
    • [译] PEP 3155--类和方法的特定名称
    • [译]pep 3333 -- Python Web 服务器网关接口 v1.0.1
  • Python工匠系列

  • 高阶知识点

  • Python 学习资源待整理
  • 设计模式

  • 好“艹蛋”的 Python 呀!
  • FIFO | 待学清单📝
  • pip 安装及使用
  • 数据分析

  • 源码阅读计划

  • OOP

  • 关于 python 中的 setup.py
  • 并行分布式框架 Celery
  • 七种武器,让你的代码提高可维护性
  • 使用 pdb 调试 Python 代码
  • 每周一个 Python 标准库
  • 🐍Python
  • PEP
佚名
2019-11-27
目录

[译] PEP 328--导入多行及绝对/相对

PEP 原文:https://www.python.org/dev/peps/pep-0328/

创建日期:2003-10-21

合入版本:2.4

译者:Lance_Van (opens new window)

# 摘要

import声明存在两个问题:

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

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

# Timeline

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

  __future__ import absolute_import

1
2

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

# 使用括号的原因

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

  • 利用反斜杠分隔开:

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

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

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

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

1
2
3

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

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

# 使用绝对导入的原因

在 Python 2.4 和更早的版本中,

  import foo

1
2

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

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

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

  from __future__ import absolute_import

1
2

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

# 使用相对导入的原因

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

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

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

  • Guido 的导入方式

    from .foo import bar
    
    
    1
    2

以及

  from ...foo import bar

1
2

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

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

有些人提出使用"*"

  from *.foo import bar

1
2
  • 还有一个选择是从很多包结构中导入: 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] (opens new window)相对导入要在导入路径前面加一个.表示当前的包,两个或者更多的.表示在当前包的父包中进行相对导入操作,一个.表示一个层级。以下是一个包的样例:

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

1
2
3
4
5
6
7
8
9
10
11

假设所在的文件是moduleX.py或subpackage1/__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

1
2
3
4
5
6
7
8
9

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

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

  import XXX.YYY.ZZZ

1
2

操作后,

  XXX.YYY.ZZZ

1
2

可以在表达式中使用,而

 .module

1
2

不能在表达式中使用。

# 相对导入与__name__属性

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

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

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

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

# 参考资料

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

  • Re: Christmas Wishlist (opens new window)
  • Re: Python-Dev Digest, Vol 5, Issue 57 (opens new window)
  • Relative import (opens new window)
  • Another Strategy for Relative Import (opens new window) [1]http://mail.python.org/pipermail/python-dev/2004-March/043739.html (opens new window) [2]https://www.python.org/doc/essays/packages/ (opens new window)

# 版权所有

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

编辑 (opens new window)
#pep
上次更新: 2024-07-15, 08:03:22
[译] PEP 318--函数和方法的装饰器
[译]pep 333 -- Python Web 服务器网关接口 v1.0

← [译] PEP 318--函数和方法的装饰器 [译]pep 333 -- Python Web 服务器网关接口 v1.0→

最近更新
01
提升沟通亲和力的实用策略
03-26
02
工作
07-15
03
如何选房子
06-25
更多文章>
Theme by Vdoing | Copyright © 2019-2025 IMOYAO | 别院牧志
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式