python中的import涉及的绝对/相对引用(python官方PEP328文档)

来源:互联网 发布:js时间转换成时间戳 编辑:程序博客网 时间:2024/06/06 13:31

通过后面文档的翻译,先简单总结一下结论:

一、关于from … import …写得太长的问题:
from xxx import aaa,bbb,ccc…如果后面比较长的话,可以使用:
from xxx import (aaa,bbb,ccc,
ddd,eee,fff…)
这个特性python2.4以后就有了。

二、关于绝对引用和相对引用:
from .abc import …是相对引用(开头带点的),一个点指当前目录找,两个点上一级目录,以此类推;
from abc import … 是绝对引用(正常开头的),系统设定的包搜寻目录里找;
import abc 永远是绝对引用;
import .abc 是不允许的;

三、补充一点:
之前网上看到有人说尽量都用import abc这种绝对引用,代码风格比较清晰。但是后来发现python很多知名的库或是标准文档中大量使用from … import …,我就搞不懂了,所以回过头来研究了一下这个。
其实,from … import …和import …都是可以用的,关键是看什么场景。
from … import …可以把包或模块引入到当前的名字空间,而import …如果后面名字较长的话最好再加用as。
另外,还有一些细节,多看代码之后会明白,到时再写。

感兴趣的同学可以继续看后面的原文和翻译,欢迎指正:


PEP 328 – Imports: Multi-Line and Absolute/Relative

PEP 328 – 多行的import和绝对/相对引用


PEP: 328 Title: Imports: Multi-Line and Absolute/Relative Author: Aahz aahz at pythoncraft.com Status: Final Type: Standards Track Created: 21-Dec-2003 Python-Version: 2.4, 2,5, 2.6 Post-History: 8-Mar-2004

Contents

  • Abstract
  • Timeline
  • Rationale for Parentheses
  • Rationale for Absolute Imports
  • Rationale for Relative Imports
  • Guido’s Decision
  • Relative Imports and name
  • Relative Imports and Indirection Entries in sys.modules
  • References
  • Copyright

Abstract

The importstatement has two problems:

  • Long importstatements can be difficult to write, requiring various contortions to fit Pythonic style guidelines.
  • 很长的import语句会比较难写,需要各种变通才能符合python风格的编程指导原则。
  • Imports can be ambiguous in the face of packages; within a package, it’s not clear whether import foorefers to a module within the package or some module outside the package. (More precisely, a local module or package can shadow another hanging directly off sys.path.)
  • 在包中,imports是不明确的;在一个包里,import foo到底是引用了一个包内的模块还是包外的另一个模块,这点不是很清楚。(更准确的说,一个本地的模块或包能够直接把sys.path下面的内容import过来)

For the first problem, it is proposed that parentheses be permitted to enclose multiple names, thus allowing Python’s standard mechanisms for multi-line values to apply. For the second problem, it is proposed that all importstatements be absolute by default (searching sys.pathonly) with special syntax (leading dots) for accessing package-relative imports.

对于第一个问题,建议允许使用圆括号把多个名字组合在一起,这样的话,就可以利用python的标准机制实现多行的值。对于第二个问题,建议所有的import语句默认是采用绝对引用(仅搜索sys.path),而特定的语法(开头带个点)可以采用针对特定包的相对引用。

Timeline

In Python 2.5, you must enable the new absolute import behavior with

from __future__ import absolute_import

You may use relative imports freely. In Python 2.6, any importstatement that results in an intra-package import will raiseDeprecationWarning(this also applies to from <> importthat fails to use the relative import syntax).

Rationale for Parentheses

Currently, if you want to import a lot of names from a module or package, you have to choose one of several unpalatable options:

  • Write a long line with backslash continuations:

    from Tkinter import Tk, Frame, Button, Entry, Canvas, Text, \  LEFT, DISABLED, NORMAL, RIDGE, END
  • Write multiple importstatements:

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

( import *is *not *an option ;-)

Instead, it should be possible to use Python’s standard grouping mechanism (parentheses) to write the importstatement:

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

This part of the proposal had BDFL approval from the beginning.

Parentheses support was added to Python 2.4.

Rationale for Absolute Imports

import绝对引用的基本原理

In Python 2.4 and earlier, if you’re reading a module located inside a package, it is not clear whether

import foo

refers to a top-level module or to another module inside the package. As Python’s library expands, more and more existing package internal modules suddenly shadow standard library modules by accident. It’s a particularly difficult problem inside packages because there’s no way to specify which module is meant. To resolve the ambiguity, it is proposed that foowill always be a module or package reachable from sys.path. This is called an absolute import.

The python-dev community chose absolute imports as the default because they’re the more common use case and because absolute imports can provide all the functionality of relative (intra-package) imports – albeit at the cost of difficulty when renaming package pieces higher up in the hierarchy or when moving one package inside another.

Because this represents a change in semantics, absolute imports will be optional in Python 2.5 and 2.6 through the use of

from __future__ import absolute_import

This part of the proposal had BDFL approval from the beginning.

Rationale for Relative Imports

import相对引用的基本原理

With the shift to absolute imports, the question arose whether relative imports should be allowed at all. Several use cases were presented, the most important of which is being able to rearrange the structure of large packages without having to edit sub-packages. In addition, a module inside a package can’t easily import itself without relative imports.

Guido approved of the idea of relative imports, but there has been a lot of disagreement on the spelling (syntax). There does seem to be agreement that relative imports will require listing specific names to import (that is, import fooas a bare term will always be an absolute import).

Here are the contenders:

  • One from Guido:

    from .foo import bar

    and

    from ...foo import bar

    These two forms have a couple of different suggested semantics. One semantic is to make each dot represent one level. There have been many complaints about the difficulty of counting dots. Another option is to only allow one level of relative import. That misses a lot of functionality, and people still complained about missing the dot in the one-dot form. The final option is to define an algorithm for finding relative modules and packages; the objection here is “Explicit is better than implicit”. (The algorithm proposed is “search up from current package directory until the ultimate package parent gets hit”.)

    Some people have suggested other punctuation as the separator, such as “-” or “^”.

    Some people have suggested using “*”:

    from *.foo import bar
  • The next set of options is conflated from several posters:

    from __pkg__.__pkg__ import

    and

    from .__parent__.__parent__ import

    Many people (Guido included) think these look ugly, but they *are *clear and explicit. Overall, more people prefer __pkg__as the shorter option.

  • One suggestion was to allow only sibling references. In other words, you would not be able to use relative imports to refer to modules higher in the package tree. You would then be able to do either

    from .spam import eggs

    or

    import .spam.eggs
  • Some people favor allowing indexed parents:

    from -2.spam import eggs

    In this scenario, importing from the current directory would be a simple

    from .spam import eggs
  • Finally, some people dislike the way you have to change importto from ... importwhen you want to dig inside a package. They suggest completely rewriting the importsyntax:

    from MODULE import NAMES as RENAME searching HOW

    or

    import NAMES as RENAME from MODULE searching HOW  [from NAMES] [in WHERE] import ...

    However, this most likely could not be implemented for Python 2.5 (too big a change), and allowing relative imports is sufficiently critical that we need something now (given that the standard importwill change to absolute import). More than that, this proposed syntax has several open questions:

    • What is the precise proposed syntax? (Which clauses are optional under which circumstances?)

    • How strongly does the searchingclause bind? In other words, do you write:

    import foo as bar searching XXX, spam as ham searching XXX

    or:

    import foo as bar, spam as ham searching XXX

Guido’s Decision

最终的决定(Guido是创立python的大神)

Guido has Pronounced [1] that relative imports will use leading dots. A single leading dot indicates a relative import, starting with the current package. Two or more leading dots give a relative import to the parent(s) of the current package, one level per dot after the first. Here’s a sample package layout:

Guido已经宣布,import相对引用使用开头带个点的语法表示。单个的点表示从当前包开始的相对引用,两个或更多的点表示从当前包的上级目录(每多一个点就上一级)开始的相对引用。这里有一个包的示例:

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

Assuming that the current file is either moduleX.pyor subpackage1/__init__.py, following are correct usages of the new syntax:

假定当前的文件是moduleX.pysubpackage1/__init__.py,以下均为正确的使用方法:

from .moduleY import spamfrom .moduleY import spam as hamfrom . import moduleYfrom ..subpackage1 import moduleYfrom ..subpackage2.moduleZ import eggsfrom ..moduleA import foofrom ...package import barfrom ...sys import path

Note that while that last case is legal, it is certainly discouraged (“insane” was the word Guido used).

需要注意的是,虽然最后一个例子(from …sys import path)是合法的,但是应尽量避免这么用。

Relative imports must always use from <> import; import <>is always absolute. Of course, absolute imports can use from <> importby omitting the leading dots. The reason import .foois prohibited is because after

相对引用必须使用from <> import的形式;imprt <>总是使用绝对引用。当然,from <> import如果省略开头的那个点,也是绝对引用。而import .foo这种写法是被禁止的,主要是因为:

import XXX.YYY.ZZZ

then

XXX.YYY.ZZZ

is usable in an expression. But

.moduleY

is not usable in an expression.

在import xxx.yyy.zzz之后,xxx.yyy.zzz是一个可用的表达式;而.moduleY却是个非法的表达式。

Relative Imports and name

import相对引用和name属性

Relative imports use a module’s name attribute to determine that module’s position in the package hierarchy. If the module’s name does not contain any package information (e.g. it is set to ‘main‘) then relative imports are resolved as if the module were a top level module, regardless of where the module is actually located on the file system.

import相对引用使用了模块的name属性去决定模块在包的继承层次中的位置。如果模块的name属性不包含任何包的信息(例如,设置成’main’),那么import相对引用会认为引入的模块是顶层的模块,而不管模块实际是在文件系统的哪个位置。

备注:我在python3.6.1版本中尝试了一下,好像__name__属性是没有影响的,但是另外有一个__package__属性是记录包的信息的,import相对引用是使用__package__属性进行判断的,如果把__package__属性改掉,相对引用会出错。这个可能是这个文档比较早,后续python的实现改进过了的缘故。

Relative Imports and Indirection Entries in sys.modules

import相对引用和sys.modules中的间接入口

When packages were introduced, the concept of an indirection entry in sys.modules came into existence [2] . When an entry in sys.modules for a module within a package had a value of None, it represented that the module actually referenced the top-level module. For instance, ‘Sound.Effects.string’ might have a value of None in sys.modules. That meant any import that resolved to that name actually was to import the top-level ‘string’ module.

当一个包被引入时,sys.modules中存在一个间接入口的概念。如果sys.modules中一个模块的入口是None值的话,就意味着这个模块实际上是应该指向相应的顶层模块。例如:在sys.modules中,’sound.effects.string’可能具有None值,这说明任何对于这个模块的引入实际上是import了顶层的’string’模块。

This introduced an optimization for when a relative import was meant to resolve to an absolute import. But since this PEP makes a very clear delineation between absolute and relative imports, this optimization is no longer needed. When absolute/relative imports become the only import semantics available then indirection entries in sys.modules will no longer be supported.

这实际上是引入了一种将相对引用解释成绝对引用的优化手段(我理解是有些地方为了保持一致性风格,相对引用实际是指向了类似sound.effects.string的模块,而这个模块实际上是一个顶层的模块,所以才需要这种机制)。但是由于这个PEP在import绝对引用和相对引用之间划定了一条清晰的界限,这种优化手段今后将不再需要。当以后import绝对/相对引用成为唯一可用的语义时,sys.modules中的间接入口也将不再被支持。

References

For more background, see the following python-dev threads:

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

Copyright

This document has been placed in the public domain.

Source:

https://github.com/python/peps/blob/master/pep-0328.txt

原创粉丝点击