摘要:相對(duì)導(dǎo)入相對(duì)導(dǎo)入使用模塊的決定它是否在一個(gè)包內(nèi)。當(dāng)你是用類似進(jìn)行相對(duì)導(dǎo)入的時(shí)候,點(diǎn)表明在包的層次中上升多少。所以,你不能在交互式會(huì)話中直接使用任何相對(duì)導(dǎo)入。
源題目與答案地址如下http://stackoverflow.com/questions/14132...。下面是我的翻譯(看作機(jī)翻也行),以及原文。
這個(gè)問題是如何解決在相對(duì)導(dǎo)入的時(shí)候,如果出現(xiàn)"System Error"的時(shí)候的解決方案。順帶一提,這個(gè)問題好像出在源碼上,在issue 18018得到解決,附上這個(gè)據(jù)說可以解決問題的地址:解決方案。我不知道怎么使用,希望知道的讀者(如果有的話)可以告訴我~
腳本VS模塊這里是解釋。長話短說,這是因?yàn)樵谶\(yùn)行一個(gè)Python文件和從什么地方導(dǎo)入那個(gè)文件之間,存在一個(gè)巨大的差異。你只要明白:一個(gè)文件到底在哪里并不能決定Python覺得它在哪個(gè)包里面。此外,這實(shí)際上取決于你是如何將這個(gè)文件導(dǎo)入到Python中的。
導(dǎo)入一個(gè)Python文件有兩種方法:作為頂層文件,或者作為一個(gè)模塊。如果你直接運(yùn)行它,這個(gè)文件就會(huì)被當(dāng)作頂層文件來執(zhí)行,比如在命令行中輸入python myfile.py。如果你使用python -m myfile,或者它是通過其他文件的import語句導(dǎo)入的,那這個(gè)文件就會(huì)作為一個(gè)模塊被導(dǎo)入。一次只能有一個(gè)頂層文件;頂層文件是你一開始運(yùn)行的Python文件。
名字當(dāng)一個(gè)文件被導(dǎo)入的時(shí)候,它會(huì)得到一個(gè)名字(存儲(chǔ)在其__name__屬性中)。如果它是作為頂層文件被導(dǎo)入的,那么它的__name__就是__main__;如果它是作為一個(gè)模塊被導(dǎo)入的,則它的__name__就是它的文件名,先于任何它所組成的包或子包,由點(diǎn)號(hào)分開。
所以,看看你這里的例子
package/ __init__.py subpackage1/ __init__.py moduleX.py moduleA.py enter code here
如果你導(dǎo)入moduleX(注意,導(dǎo)入而非運(yùn)行),那么它的名字就是package.subpackage1.moduleX。如果你導(dǎo)入moduleA,則它的名字就是package.moduleA。可是,如果你直接從命令行運(yùn)行moduleX,則它的名字就會(huì)被__main__取而代之,moduleA也是如此。當(dāng)一個(gè)模塊作為頂層文件被運(yùn)行的時(shí)候,其會(huì)失去本身的名字,并由__main__取而代之。
不通過包含它的包來獲取一個(gè)模塊這里有一個(gè)附送的小技巧:模塊名取決于它是從所在的目錄直接導(dǎo)入,或者通過一個(gè)包導(dǎo)入的。這只有在你從目錄中運(yùn)行Python,以及嘗試在相同的目錄(或者它的子目錄)導(dǎo)入一個(gè)文件的時(shí)候有差別。舉個(gè)例子,如果你在目錄package/subpackage1運(yùn)行Python解釋器,然后導(dǎo)入moduleX,moduleX的名字就只會(huì)是moduleX,而不是package.subpackage1.moduleX。這是因?yàn)椋琍ython將當(dāng)前的路徑添加到模塊搜索路徑的開頭;如果它發(fā)現(xiàn)當(dāng)前目錄有一個(gè)需要運(yùn)行的模塊,它不會(huì)明白這個(gè)目錄是包的一部分,而這個(gè)包的信息也不會(huì)成為模塊名的一部分。
如果你只是交互式地運(yùn)行解釋器,會(huì)出現(xiàn)一個(gè)特殊情況(比如:輸入python并進(jìn)入shell)。這種情況下,這個(gè)交互式會(huì)話的名字是__main__。
你的錯(cuò)誤實(shí)際上是:如果一個(gè)模塊名沒有點(diǎn),它不會(huì)被視作包的一部分。這個(gè)文件實(shí)際上在哪個(gè)目錄無關(guān)緊要。唯一相關(guān)的是,它的名字是什么,而它的名字取決于你是如何導(dǎo)入它的。
現(xiàn)在,看看你在問題中所引用的內(nèi)容:
相對(duì)導(dǎo)入……相對(duì)導(dǎo)入使用一個(gè)模塊的__name__屬性來決定模塊在包中的層次。如果模塊的名字不包含任何模塊信息(比如被設(shè)置為__main__),那么相對(duì)導(dǎo)入將會(huì)把該模塊視作頂層模塊,忽視其在文件系統(tǒng)中的實(shí)際位置。
相對(duì)導(dǎo)入使用模塊的__name__決定它是否在一個(gè)包內(nèi)。當(dāng)你是用類似form .. import foo進(jìn)行相對(duì)導(dǎo)入的時(shí)候,點(diǎn)表明在包的層次中上升多少。舉個(gè)例子,如果你當(dāng)前的模塊的名字是package.subpackage1.moduleX,那么..moduleA就表示模塊package.moduleA。要想讓from .. import語句起作用,模塊的名字至少有在import語句中的點(diǎn)的數(shù)量。
... 只是在包中是相對(duì)的可還是,如果你的模塊名是__main__,那么它不會(huì)被當(dāng)作一個(gè)包。它的名字里面沒有點(diǎn),因此你不能在文件內(nèi)使用from .. import 語句。如果你嘗試這么干,你會(huì)獲得錯(cuò)誤relative-import in non-package。
腳本不可以相對(duì)地導(dǎo)入你想做的事情大概是嘗試要從命令行中運(yùn)行moduleX。當(dāng)你這么干的時(shí)候,它的名字會(huì)被設(shè)置為__main__,這意味著里面的相對(duì)導(dǎo)入失效了,因?yàn)椋核拿植]有顯示出它在一個(gè)包里面。注意,這會(huì)發(fā)生在你從相同的目錄運(yùn)行中運(yùn)行Python并試圖導(dǎo)入那個(gè)模塊的時(shí)候,這是因?yàn)椋喝缟纤f,python會(huì)在意識(shí)到這是包的一部分之前,在當(dāng)前目錄下“過早”找到那個(gè)模塊。
你也要記得,當(dāng)你運(yùn)行一個(gè)交互式解釋器的時(shí)候,交互式會(huì)話的name總是__main__。所以,你不能在交互式會(huì)話中直接使用任何相對(duì)導(dǎo)入。相對(duì)導(dǎo)入只能使用在模塊文件內(nèi)。
兩個(gè)解決方案:
如果你真的向直接運(yùn)行moduleX,但你希望它可以被視作包的一部分,那使用python -m package.subpackage.moduleX運(yùn)行即可。選項(xiàng)-m告訴Python將其作為一個(gè)模塊而非頂層文件導(dǎo)入。
如果你不不希望真的運(yùn)行moduleX,你只想運(yùn)行其他使用了在moduleX里的函數(shù)的腳本,如myfile.py。在這種嗯情況下,將myfile.py放到其他地方——不在包目錄里面——并運(yùn)行它。如果在myfile.py里面,你做點(diǎn)類似從package.moduleA里面導(dǎo)入spam,它會(huì)做的很好~
注意事項(xiàng):
對(duì)于這兩個(gè)解決方法的任意一個(gè)來說,包目錄必須在模塊搜索路徑sys.path中。如果不是的話,你不能確實(shí)可靠地使用包里面的任何東西。
自從Python2.6以來,包依賴的解決不僅僅取決于模塊的名字,還有模塊的__package屬性。這使我為什么避免使用__name__來指代模塊的名字。一個(gè)模塊的名字現(xiàn)在可能是__package__ + __name__了,除非沒有包。
原文如下:
Script vs. Module
Here"s an explanation. The short version is that there is a big difference between directly running a Python file, and importing that file from somewhere else. Just knowing what directory a file is in does not determine what package Python thinks it is in. That depends, additionally, on how you load the file into Python (by running or by importing).
There are two ways to load a Python file: as the top-level script, or as a module. A file is loaded as the top-level script if you execute it directly, for instance by typing python myfile.py on the command line. It is loaded as a module if you do python -m myfile, or if it is loaded when an import statement is encounted inside some other file. There can only be one top-level script at a time; the top-level script is the Python file you ran to start things off.
Naming
When a file is loaded, it is given a name (which is stored in its name attribute). If it was loaded as the top-level script, its name is __main__. If it was loaded as a module, its name is the filename, preceded by the names of any packages/subpackages of which it is a part, separated by dots.
So for instance in your example:
package/
__init__.py subpackage1/ __init__.py moduleX.py moduleA.py
enter code here
if you imported moduleX (note: imported, not directly executed), its name would be package.subpackage1.moduleX. If you imported moduleA, its name would be package.moduleA. However, if you directly run moduleX from the command line, its name will instead be __main__, and if you directly run moduleA from the command line, its name will be __main__. When a module is run as the top-level script, it loses its normal name and its name is instead __main__.
Accessing a module NOT through its containing package
There is an additional wrinkle: the module"s name depends on whether it was imported "directly" from the directory it is in, or imported via a package. This only makes a difference if you run Python in a directory, and try to import a file in that same directory (or a subdirectory of it). For instance, if you start the Python interpreter in the directory package/subpackage1 and then do import moduleX, the name of moduleX will just be moduleX, and not package.subpackage1.moduleX. This is because Python adds the current directory to its search path on startup; if it finds the to-be-imported module in the current directory, it will not know that that directory is part of a package, and the package information will not become part of the module"s name.
A special case is if you run the interpreter interactively (e.g., just type python and start entering Python code on the fly). In this case the name of that interactive session is __main__.
Now here is the crucial thing for your error message: if a module"s name has no dots, it is not considered to be part of a package. It doesn"t matter where the file actually is on disk. All that matters is what its name is, and its name depends on how you loaded it.
Now look at the quote you included in your question:
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.
Relative imports...
Relative imports use the module"s name to determine where it is in a package. When you use a relative import like from .. import foo, the dots indicate to step up some number of levels in the package hierarchy. For instance, if your current module"s name is package.subpackage1.moduleX, then ..moduleA would mean package.moduleA. For a from .. import to work, the module"s name must have at least as many dots as there are in the import statement.
... are only relative in a package
However, if your module"s name is __main__, it is not considered to be in a package. Its name has no dots, and therefore you cannot use from .. import statements inside it. If you try to do so, you will get the "relative-import in non-package" error.
Scripts can"t import relative
What you probably did is you tried to run moduleX or the like from the command line. When you did this, its name was set to __main__, which means that relative imports within it will fail, because its name does not reveal that it is in a package. Note that this will also happen if you run Python from the same directory where a module is, and then try to import that module, because, as described above, Python will find the module in the current directory "too early" without realizing it is part of a package.
Also remember that when you run the interactive interpreter, the "name" of that interactive session is always __main__. Thus you cannot do relative imports directly from an interactive session. Relative imports are only for use within module files.
Two solutions:
If you really do want to run moduleX directly, but you still want it to be considered part of a package, you can do python -m package.subpackage.moduleX. The -m tells Python to load it a s a module, not as the top-level script. Or perhaps you don"t actually want to run moduleX, you just want to run some other script, say myfile.py, that uses functions inside moduleX. If that is the case, put myfile.py somewhere else --- not inside the package directory -- and run it. If inside myfile.py you do things like from package.moduleA import spam, it will work fine.
Notes
For either of these solutions, the package directory (package in your example) must be accessible from the Python module search path (sys.path). If it is not, you will not be able to use anything in the package reliably at all. since Python 2.6, the module"s "name" for package-resolution purposes is determined not just by its __name__ attributes but also by the __package__ attribute. That"s why I"m avoiding using the explicit symbol __name__ to refer to the module"s "name". Since Python 2.6 a module"s "name" is effectively __package__ + "." + __name__, or just __name__ if __package__ is None.)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/37851.html
摘要:包中的一個(gè)模塊可以采用相對(duì)路徑導(dǎo)入包,不影響模塊功能一個(gè)腳本未成為模塊,即其目錄及父目錄內(nèi)無可以采用相對(duì)路徑導(dǎo)入包,并以腳本模式運(yùn)行。參考相對(duì)導(dǎo)入與絕對(duì)導(dǎo)入 絕對(duì)路徑導(dǎo)入格式為import a.b或者from a import b,相對(duì)路徑導(dǎo)入格式為from . import b或者from ..a import b。 python2默認(rèn)為相對(duì)路徑導(dǎo)入,python3默認(rèn)為絕對(duì)路徑導(dǎo)...
摘要:標(biāo)準(zhǔn)模塊附帶了一個(gè)標(biāo)準(zhǔn)模塊庫。它返回一個(gè)如果調(diào)用不傳遞參數(shù),則列出當(dāng)前已經(jīng)定義的所有名字用可以查看所有的內(nèi)置類型變量函數(shù)等,方法是借助標(biāo)準(zhǔn)模塊模塊高級(jí)技巧總結(jié)的搜索路徑,順序一定要搞得清編譯后的文件內(nèi)置函數(shù)查看模塊定義的名字。 上一節(jié),我們講解了Python模塊的基礎(chǔ)知識(shí),這一節(jié)我們繼續(xù)深入了解模塊的更多知識(shí),從而讓大家全面了解、掌握和運(yùn)用模塊到我們實(shí)際的編程中。 在上一節(jié)中有一句話接...
摘要:模塊可以導(dǎo)入和導(dǎo)出各種類型的變量,如函數(shù),對(duì)象,字符串,數(shù)字,布爾值,等等。所以這可能會(huì)導(dǎo)致一些不符合預(yù)期的行為。可變的基本類型值在導(dǎo)入一些基本類型的值如數(shù)字,布爾值或字符串時(shí),可能會(huì)產(chǎn)生一個(gè)有趣的副作用。 前言 ECMAScript 2015(又稱ES6)提供了一個(gè)前端JavaScript缺失已久的特性 —— 模塊。ES2015中的模塊參考了CommonJS規(guī)范(目前Node.js的...
摘要:前綴命名空間如果命名空間的目的是避免沖突的話。語言程序經(jīng)常使用前綴命名空間。我認(rèn)為前綴命名空間是中最清楚明白的命名空間系統(tǒng)。對(duì)象命名空間的一個(gè)問題是它會(huì)導(dǎo)致與面向?qū)ο笙鬟f混淆。嵌套命名空間的幻覺在中也存在。 原文鏈接:《JavaScript Namespacing》譯文原鏈:【譯】JavaScript 命名空間 JavaScript 中有很多可以給你的對(duì)象安全分配命名空間的方法。這...
摘要:的文本檢測器是一種基于新穎架構(gòu)和訓(xùn)練模式的深度學(xué)習(xí)模型。深度學(xué)習(xí)文本檢測器圖文本檢測全卷積網(wǎng)絡(luò)的結(jié)構(gòu)等人的圖。隨著和的發(fā)布,我們現(xiàn)在可以使用一種名為的基于深度學(xué)習(xí)的文本檢測器,它基于等人的年論文一種高效精確的場景文本檢測器。 by Adrian Rosebrock on August 20, 2018 in Deep Learning, Optical Character Recogn...
閱讀 3199·2021-09-29 09:34
閱讀 3551·2021-09-10 10:51
閱讀 1948·2021-09-10 10:50
閱讀 6731·2021-08-12 13:31
閱讀 3000·2019-08-30 15:54
閱讀 1560·2019-08-30 15:44
閱讀 1430·2019-08-29 12:26
閱讀 2654·2019-08-26 18:36