最近在做微信公眾平臺(tái)的后臺(tái)開發(fā),找到了一個(gè)Python的微信SDKwechat-python-sdk伟恶,使用之后卻發(fā)現(xiàn)不支持Python3儒溉,于是決定移植到Python3上面。
在移植的過(guò)程中须妻,發(fā)現(xiàn)原來(lái)的代碼在import不能正確導(dǎo)入同一package下的module,在網(wǎng)上搜尋方案無(wú)果泛领,怒翻譯Python官方的PEP 0328
感謝chickenjohn桑在翻譯過(guò)程中給予的幫助荒吏。也希望各位多給予指導(dǎo)。
目錄
摘要
Timeline
使用括號(hào)的原因
使用絕對(duì)導(dǎo)入的原因
使用相對(duì)導(dǎo)入的原因
Guido的選擇
相對(duì)導(dǎo)入與__name__
屬性
相對(duì)導(dǎo)入與sys.modules
中的間接尋址入口
參考資料
版權(quán)所有
摘要
import
聲明存在兩個(gè)問(wèn)題:
- 過(guò)長(zhǎng)的
import
聲明很難寫渊鞋,可能為了符合Python編碼規(guī)范出現(xiàn)很多換行绰更。 - 存在很多包的情況下,
import
操作可能存在語(yǔ)義含糊不清的情況锡宋;例如儡湾,在一個(gè)包中,import foo
操作可能代表導(dǎo)入了包內(nèi)的foo
模塊员辩,也可能代表導(dǎo)入了包外的foo
模塊盒粮。(更準(zhǔn)確的說(shuō),一個(gè)本地的模塊或包可能直接切斷了與外部(即sys.path
)的聯(lián)系奠滑。)
對(duì)于第一個(gè)問(wèn)題丹皱,我們建議用括號(hào)將要導(dǎo)入的名稱括起來(lái),以滿足Python的換行標(biāo)準(zhǔn)宋税。對(duì)于第二個(gè)問(wèn)題摊崭,我們建議所有的import
默認(rèn)以絕對(duì)路徑的方式聲明,并用特殊語(yǔ)法(即開頭的.
)表示相對(duì)路徑杰赛。
Timeline
在Python 2.5中呢簸,加入以下語(yǔ)句可以應(yīng)用新的絕對(duì)路徑標(biāo)準(zhǔn):
__future__ import absolute_import
如此就能優(yōu)雅的使用相對(duì)路徑導(dǎo)入了。在Python 2.6中乏屯,任何出現(xiàn)包內(nèi)導(dǎo)入的import
操作都會(huì)引起DeprecationWarning
(這對(duì)于沒(méi)有使用相對(duì)導(dǎo)入語(yǔ)法的from <> import
操作同樣適用)根时。
使用括號(hào)的原因
現(xiàn)在,如果要從一個(gè)模塊或包中導(dǎo)入很多名稱時(shí)辰晕,你不得不從如下不夠優(yōu)雅的方式中做出選擇:
-
利用反斜杠分隔開:
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 *
的情況 ;-)
作為替代蛤迎,應(yīng)使用Python標(biāo)準(zhǔn)的分組機(jī)制進(jìn)行import
操作:
from Tkinter import (Tk, Frame, Button, Entry, Canvas, Text,
LEFT, DISABLED, NORMAL, RIDGE, END)
這個(gè)建議從提出開始就被BDFL審批。
Python 2.4版本開始引入這種括號(hào)的支持
使用絕對(duì)導(dǎo)入的原因
在Python 2.4和更早的版本中含友,
import foo
這個(gè)語(yǔ)句可能指代一個(gè)庫(kù)中的頂層模塊替裆,也可能指代另一個(gè)本地包中的模塊校辩。作為Python標(biāo)準(zhǔn)庫(kù)的擴(kuò)展,越來(lái)越多的包內(nèi)模塊無(wú)意中與Python標(biāo)準(zhǔn)庫(kù)的同名模塊產(chǎn)生了沖突辆童。這個(gè)問(wèn)題導(dǎo)致了很多時(shí)候無(wú)法確定它導(dǎo)入了哪一個(gè)模塊宜咒,從而產(chǎn)生歧義。為了消除這個(gè)歧義把鉴,我們建議此種方式導(dǎo)入的foo
必須是在sys.path
中可以找到的模塊或包故黑。此方式的導(dǎo)入稱為絕對(duì)導(dǎo)入。
Python-dev社區(qū)默認(rèn)選用絕對(duì)導(dǎo)入的原因是這種方式在實(shí)際中更常用纸镊,而且能提供所有使用相對(duì)導(dǎo)入時(shí)可提供的功能倍阐,盡管這可能導(dǎo)致一系列麻煩:例如修改頂層包名稱以及修改包目錄結(jié)構(gòu)。
因?yàn)檫@可能導(dǎo)致語(yǔ)義上的變動(dòng)逗威,在Python 2.5和2.6中,絕對(duì)導(dǎo)入不是必須遵守的岔冀,加入以下語(yǔ)句可以應(yīng)用絕對(duì)引用標(biāo)準(zhǔn):
from __future__ import absolute_import
這個(gè)建議從提出開始就被BDFL審批凯旭。
使用相對(duì)導(dǎo)入的原因
與絕對(duì)導(dǎo)入相對(duì)的,是否允許相對(duì)導(dǎo)入的問(wèn)題也出現(xiàn)了使套。示例如下罐呼,這些示例的重點(diǎn)在于如何規(guī)整大包的結(jié)構(gòu)而不必在大包的子包中做改動(dòng)。除此之外侦高,不使用相對(duì)導(dǎo)入很難單獨(dú)導(dǎo)入包內(nèi)的一個(gè)模塊嫉柴。
Guido認(rèn)可相對(duì)導(dǎo)入這種導(dǎo)入方式,但是相對(duì)導(dǎo)入在語(yǔ)法上可能產(chǎn)生很多歧義奉呛。有一個(gè)不成文的約定就是相對(duì)導(dǎo)入需要列出導(dǎo)入的的具體名稱(就是說(shuō)计螺,形如import foo
單獨(dú)的導(dǎo)入被認(rèn)為是絕對(duì)導(dǎo)入)。
不同的相對(duì)導(dǎo)入方式如下:
-
Guido的導(dǎo)入方式
from .foo import bar
以及
from ...foo import bar
這兩種形式有很多不同的解釋方式瞧壮。 一種解釋方式是一個(gè).
表示文件結(jié)構(gòu)中的一個(gè)層級(jí)登馒。這樣的話有很多人抱怨,數(shù).
的個(gè)數(shù)很麻煩咆槽,顯然不夠優(yōu)雅陈轿。另外一個(gè)選擇是只允許一個(gè)文件層次之間的相對(duì)導(dǎo)入。這樣又會(huì)造成很多功能上的喪失秦忿,還有很多人抱怨在這種表示下會(huì)忘記.
麦射。最終的方案是聲明一種相對(duì)導(dǎo)入尋找包與模塊的算法,而這又違反了“The Zen of Python”中的"Explicit is better than implicit"(外顯勝于內(nèi)隱)灯谣。(這個(gè)被提議的算法主要思想是“自下而上潜秋,直至觸頂”)
有些人提出使用其他標(biāo)點(diǎn)符號(hào)作為分隔符,比如“-”或者"^"酬屉。
有些人提出使用"*"
from *.foo import bar
- 還有一個(gè)選擇是從很多包結(jié)構(gòu)中導(dǎo)入:
from pkg.pkg import
與
from parent.parent import
很多人(包括Guido)認(rèn)為這種方式看起來(lái)很丑半等,但是這種方式非常明確而且一目了然揍愁。 總之,更多人喜歡以__pkg__
作為更短的選項(xiàng)杀饵。
有人提出只允許同一文件層級(jí)之間的引用莽囤。 換句話說(shuō),用相對(duì)導(dǎo)入無(wú)法導(dǎo)入更高層級(jí)的模塊切距,只能以如下方式導(dǎo)入:
from .spam import eggs
或者
import .spam.eggs有的人喜歡索引的父目錄表示方式
from -2.spam import eggs
這種方式下朽缎,從當(dāng)前目錄導(dǎo)入只需要如下方式:
from .spam import eggs最后,當(dāng)要導(dǎo)入的包處于比較深的文件結(jié)構(gòu)時(shí)谜悟,一些人不愿意從
import
的寫法改為from ... import
话肖。他們建議重寫import
的語(yǔ)法:
from MODULE import NAMES as RENAME searching HOW
或者
import NAMES as RENAME from MODULE searching HOW
[from NAMES] [in WHERE] import ...
然而,這在Python 2.5中很可能不能實(shí)現(xiàn)(改動(dòng)過(guò)大)葡幸,允許相對(duì)導(dǎo)入非常關(guān)鍵最筒,所以()除此之外,這個(gè)被建議的語(yǔ)法有很多問(wèn)題:
- 準(zhǔn)確的語(yǔ)法是什么蔚叨?(什么條件下應(yīng)用)
-
searching
字句應(yīng)對(duì)應(yīng)什么床蜘?也就是說(shuō),應(yīng)該采用一下哪種方式:
import foo as bar searching XXX, spam as ham searching XXX
或者
import foo as bar, spam as ham searching XXX
Guido的選擇
Guido已經(jīng)宣布[1]相對(duì)導(dǎo)入要在導(dǎo)入路徑前面加一個(gè).
表示當(dāng)前的包蔑水,兩個(gè)或者更多的.
表示在當(dāng)前包的父包中進(jìn)行相對(duì)導(dǎo)入操作邢锯,一個(gè).
表示一個(gè)層級(jí)。以下是一個(gè)包的樣例:
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleY.py
subpackage2/
__init__.py
moduleZ.py
moduleA.py
假設(shè)所在的文件是moduleX.py
或subpackage1/__init__.py
, 新語(yǔ)法的正確用法如下:
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
注意搀别,雖然最后一個(gè)例子中的用法是合法的丹擎,但是不推薦這樣做。(Guido用瘋狂(insane)這個(gè)詞來(lái)形容這種做法)
相對(duì)導(dǎo)入必須使用形如from <> import
的方式; 形如import <>
的均視為絕對(duì)導(dǎo)入歇父。當(dāng)然蒂培,絕對(duì)導(dǎo)入也可以通過(guò)省略.
的方式進(jìn)行from <> import
操作。 禁止使用import .foo
的原因是:在
import XXX.YYY.ZZZ
操作后庶骄,
XXX.YYY.ZZZ
可以在表達(dá)式中使用毁渗,而
.module
不能在表達(dá)式中使用。
相對(duì)導(dǎo)入與__name__
屬性
相對(duì)導(dǎo)入使用一個(gè)模塊的__name__
屬性確定模塊在包層次結(jié)構(gòu)中的位置单刁。如果模塊的名字不包含任何包的信息(比如它被設(shè)置為__main__
)灸异,相對(duì)導(dǎo)入就會(huì)以處理最頂層模塊一樣處理,無(wú)視這個(gè)模塊的實(shí)際位置羔飞。
相對(duì)導(dǎo)入與sys.modules
中的間接尋址入口
當(dāng)包的概念被引出時(shí)肺樟,在sys.modules
中間接尋址入口的概念應(yīng)運(yùn)而生[2]。當(dāng)一個(gè)sys.module
中一個(gè)包中的模塊的入口的值是None
的時(shí)候逻淌,它表示當(dāng)前模塊確實(shí)表示頂層么伯。例如,'Sound.Effects.string'
在sys.modules
的值可能是None
卡儒。這意味著導(dǎo)入對(duì)應(yīng)'Sound.Effects.string'
的操作就是導(dǎo)入string
模塊田柔。
這又引出了一個(gè)當(dāng)絕對(duì)導(dǎo)入對(duì)應(yīng)相對(duì)導(dǎo)入情況下的的優(yōu)化方式俐巴。但是在PEP對(duì)于絕對(duì)導(dǎo)入和相對(duì)導(dǎo)入有著明確界定的情況下,這種優(yōu)化方式就不再需要了硬爆。當(dāng)絕對(duì)導(dǎo)入或相對(duì)導(dǎo)入成為了唯一可用的導(dǎo)入方式時(shí)欣舵,sys.modules
中的間接尋址入口不再支持。
參考資料
了解更多相關(guān)背景可以參考以下主題:
- Re: Christmas Wishlist
- Re: Python-Dev Digest, Vol 5, Issue 57
- Relative import
-
Another Strategy for Relative Import
[1] http://mail.python.org/pipermail/python-dev/2004-March/043739.html
[2] https://www.python.org/doc/essays/packages/
版權(quán)所有
這個(gè)文檔已被放置在公共域名缀磕。
來(lái)源:https://hg.python.org/peps/file/tip/pep-0328.txt