前言
本文的文字及圖片來源於網絡,僅供學習、交流使用,不具備任何商業用途,版權歸原做者全部,若有問題請及時聯繫咱們以做處理。
做者:sys_songhtml
python中的Module是比較重要的概念。常見的狀況是,事先寫好一個.py文 件,在另外一個文件中須要import時,將事先寫好的.py文件拷貝 到當前目錄,或者是在sys.path中增長事先寫好的.py文件所在的目錄,而後import。這樣的作法,對於少數文件是可行的,但若是程序數目很 多,層級很複雜,就很吃力了。若是你剛學python不久,有問題找不到人解答的話。能夠去小編的Python交流.裙 :一久武其而而流一思(數字的諧音)轉換下能夠找到了,裏面有最新Python教程項目可拿,不懂的問題多跟裏面的人交流,都會解決哦!python
有沒有辦法,像Java的Package同樣,將多個.py文件組織起來,以便在外部統一調用,和在內部互相調用呢?答案是有的。
主要是用到python的包的概念,python __init__.py在包裏起一個比較重要的做用
要弄明白這個問題,首先要知道,python在執行import語句時,到底進行了什麼操做,按照python的文檔,它執行了以下操做:
第1步,建立一個新的,空的module對象(它可能包含多個module);
第2步,把這個module對象插入sys.module中
第3步,裝載module的代碼(若是須要,首先必須編譯)
第4步,執行新的module中對應的代碼。
在執行第3步時,首先要找到module程序所在的位置,其原理爲:
如 果須要導入的module的名字是m1,則解釋器必須找到m1.py,它首先在當前目錄查找,而後是在環境變量PYTHONPATH中查找。 PYTHONPATH能夠視爲系統的PATH變量一類的東西,其中包含若干個目錄。若是PYTHONPATH沒有設定,或者找不到m1.py,則繼續搜索 與python的安裝設置相關的默認路徑,在Unix下,一般是/usr/local/lib/python。
事實上,搜索的順序是:當前路徑 (以及從當前目錄指定的sys.path),而後是PYTHONPATH,而後是python的安裝設置相關的默認路徑。正由於存在這樣的順序,若是當前 路徑或PYTHONPATH中存在與標準module一樣的module,則會覆蓋標準module。也就是說,若是當前目錄下存在xml.py,那麼執 行import xml時,導入的是當前目錄下的module,而不是系統標準的xml。
瞭解了這些,咱們就能夠先構建一個package,以普通module的方式導入,就能夠直接訪問此package中的各個module了。
Python中的package定義很簡單,其層次結構與程序所在目錄的層次結構相同,這一點與Java相似,惟一不一樣的地方在於,python中的package必須包含一個__init__.py的文件。
例如,咱們能夠這樣組織一個package:
package1/
__init__.py
subPack1/
__init__.py
module_11.py
module_12.py
module_13.py
subPack2/
__init__.py
module_21.py
module_22.py
……
__init__.py能夠爲空,只要它存在,就代表此目錄應被做爲一個package處理。固然,__init__.py中也能夠設置相應的內容,下文詳細介紹。
好了,如今咱們在module_11.py中定義一個函數:
def funA():
print "funcA in module_11"
return
在頂層目錄(也就是package1所在的目錄,固然也參考上面的介紹,將package1放在解釋器可以搜索到的地方)運行python:
>>>from package1.subPack1.module_11 import funcA
>>>funcA()
funcA in module_11
這樣,咱們就按照package的層次關係,正確調用了module_11中的函數。
細心的用戶會發現,有時在import語句中會出現通配符*,導入某個module中的全部元素,這是怎麼實現的呢?
答案就在__init__.py中。咱們在subPack1的__init__.py文件中寫
__all__ = ['module_13', 'module_12']
而後進入python
>>>from package1.subPack1 import *
>>>module_11.funcA()
Traceback (most recent call last):
File "", line 1, in
ImportError: No module named module_11
也就是說,以*導入時,package內的module是受__init__.py限制的。
好了,最後來看看,如何在package內部互相調用。
若是但願調用同一個package中的module,則直接import便可。也就是說,在module_12.py中,能夠直接使用
import module_11
若是不在同一個package中,例如咱們但願在module_21.py中調用module_11.py中的FuncA,則應該這樣:
from module_11包名.module_11 import funcA編程
包機制網絡
# a.py
def add_func(a,b):
return a+bapp
# b.py
from a import add_func # Also can be : import a
print ("Import add_func from module a")
print ("Result of 1 plus 2 is: ")
print (add_func(1,2)) # If using "import a" , then here should be "a.add_func"
module能夠定義在包裏面.Python定義包的方式稍微有點古怪,假設咱們有一個parent文件夾,該文件夾有一個child子文件夾.child中有一個module a.py . 如何讓Python知道這個文件層次結構?很簡單,每一個目錄都放一個名爲_init_.py 的文件.該文件內容能夠爲空.這個層次結構以下所示:函數
parent
--__init_.py
--child
-- __init_.py
--a.py
b.py
那麼Python如何找到咱們定義的module?在標準包sys中,path屬性記錄了Python的包路徑.你能夠將之打印出來:
import sys
print(sys.path)
一般咱們能夠將module的包路徑放到環境變量PYTHONPATH中,該環境變量會自動添加到sys.path屬性.另外一種方便的方法是編程中直接指定咱們的module路徑到sys.path 中:
import sys
import os
sys.path.append(os.getcwd()+'\\parent\\child')
print(sys.path)
from a import add_func
print (sys.path)
print ("Import add_func from module a")
print ("Result of 1 plus 2 is: ")
print (add_func(1,2))
知識點:post
如何定義模塊和包學習
如何將模塊路徑添加到系統路徑,以便python找到它們spa
如何獲得當前路徑.net
http://www.dai3.com/python-import.html下文地址:
兩個常見錯誤
錯誤重現
目錄樹
1
2
3
4
5
6
7
8
9
|
case1/
├──
cat
│
├── __init__.py
│
└── cat.py
├──
dog
│
├── __init__.py
│
└── dog.py
└──
main.py
|
代碼
1
2
3
|
# case1/cat/cat.py
from .. import dog
|
執行
python case1/cat/cat.py
錯誤緣由
python 使用一個模塊的屬性 name 來決定他在包結構中的位置,因此當直接執行 cat.py 時,name = \’main\’,cat.py 被看成頂層模塊來處理了,天然不可能導入上層的任何對象了。
錯誤重現
目錄樹
1
2
3
4
5
6
7
8
9
10
11
|
case2/
├──
cat
│
├── __init__.py
│
├── cat.py
│
└── cat.pyc
├──
dog
│
├── __init__.py
│
└── dog.py
├──
__init__.py
└──
main.py
|
代碼
1
2
3
4
5
6
|
# case2/cat/cat.py
from .. import dog
# case2/main.py
import cat.cat
|
執行
python case2/main.py
錯誤緣由:
這裏的 case2 是一個包,但當你直接執行 main.py 的時候,就沒有把完整的 case2 看成一個包來處理了,可想而知,下層的 cat.py 天然找不到上層包了。即想要相對導入成功,必須讓下層的被導入對象是上層包或上層包內的對象。
目錄樹
1
2
3
4
5
6
7
8
9
10
11
12
|
case3/
├──
alpaca.py
├──
main.py
└──
pets
├── __init__.py
├── cat
│ ├── __init__.py
│ └── cat.py
└── dog
├── __init__.py
└── dog.py
|
代碼
1
2
3
4
5
6
7
|
# case3/pets/cat/cat.py
from ..dog import dog
from .. import dog
# case3/main.py
from pets.cat import cat
|
執行
python case3/main.py
請注意,這裏的 cat.py 中是不能導入 alpaca 的,由於 pets 已是這個包樹的頂層了。
From:http://hiaero.net/python-relative-imports/
另一篇:
用python作項目,若是項目大了,或者想更好的管理程序,老是要使用包。包解決了命名衝突的問題。
今天在使用python的相對路徑導入的時候,遇到了很多的問題。
包導入情形:
1
2
3
4
5
6
7
8
9
10
11
|
src/
__init__.py
main.py
components/
__init__.py
expander.py
language_id.py
utilities/
__init__.py
functions.py
|
若是要在expander.py中引用functions.py中的內容,或許這樣表示
from ..utilities import functions.py
1.錯誤一:ValueError:Attemptedrelative import beyond toplevel package
這個問題是由於到達了包的最頂層,而最頂層不是一個包。
解決方法:在main.py同級添加一個目錄mod,包含components和utilities,並在mod中添加一個init.py,便可解決
參見:http://stackoverflow.com/questions/4175534/relative-imports-in-python
2.錯誤二:ValueError: Attempted relative import in non-package
使用相對路徑進行導入的文件,不能再看成主文件執行。緣由以下:
http://blog.csdn.net/chinaren0001/article/details/7338041
3.錯誤三:no module named ***
在指定路徑下沒有找到該模塊。
另外:在main.py執行的時候,沒有指定路徑的文件默認與main.py是同一路徑。本期分享到此,若是你剛學python不久,沒有最新學習路線或有問題找不到人解答的話。能夠去小編的Python交流.裙 :一久武其而而流一思(數字的諧音)轉換下能夠找到了,裏面有最新Python教程項目可拿,不懂的問題多跟裏面的人交流,都會解決哦!