目錄
- 模塊和包
- 導入包的幾種方式
- 包內(nèi)引用
- 自定義init.py
- 添加本地的包到項目中
模塊和包
首先钳榨,先介紹兩個概念:
- 模塊:一個python文件(xxx.py)就是一個模塊轿曙。我們可以在一個模塊里定義變量涡拘、方法艳狐、類
- 包:模塊通過包來組織和管理。從實現(xiàn)的方式來看毫捣,包是一個包含init.py的文件夾
導入包的幾種方式
- import item.subitem.subsubitem
- from package import item (推薦使用的方式)
- from package import *
現(xiàn)在假設我們有下面的文件結(jié)構(gòu)锋谐,michasel.py遍尺、james.py和amanda.py的代碼是類似的,除了name的值不一樣:
# 文件結(jié)構(gòu)
school
boys
michael.py
james.py
__init__.py
girls
amanda.py
__init__.py
__init__.py
# michael.py 示例代碼
name = 'Michael'
def say_hello():
print('hi, this is %s.' % (name, ))
class Info(object):
def __init__(self):
pass
def info(self):
say_hello()
默認情況下涮拗,我們不需要在init.py下添加任何代碼就可以使用上述的前兩種方式導入乾戏。
- import item.subitem.subsubitem:使用這種方法瞎疼,可以導入包或者模塊怔檩,但是不能導入一個模塊中定義的內(nèi)容,比如模塊中的類则北,方法或者變量等就漾。并且引用包中的內(nèi)容的時候呐能,必須使用完整的名字(這里就是item.subitem.subsubitem)。一般使用這種方式的時候从藤,我們可以給導入的包或者模塊起別名催跪,這樣就可以避免使用很長的完整名。
import school.boys.michael
school.boys.michael.say_hello()
michael.say_hello() # NameError: name 'michael' is not defined
# 取別名
import school.boys.james as james
james.say_hello()
- from package import item:從字面理解夷野,就是從某個包中導入子包或者模塊懊蒸。除此之外,還可以導入某個模塊中定義的類悯搔,方法或者變量等骑丸。同時,與上面那種方法相比妒貌,這種方法可以通過import后面的名字直接使用(而不需要使用完整名)通危。
from school.boys import james
james.say_hello()
from school.boys.michael import name
print(name)
- from package import *:執(zhí)行from package import * 的時候,如果init.py中定義了all列表灌曙,則會把列表中列出的模塊全部導入菊碟。如果沒有定義all列表,那么就不支持import *在刺;如果定義了all卻沒有賦值逆害,那么import *不會導入任何模塊。
# 沒有定義__all__
from school.boys import *
james.say_hello() # NameError: name 'james' is not defined
# 設置__all__ = __all__ = ['james', 'michael']
from school.boys import *
james.say_hello() # Correct
michael.say_hello() # Correct
# 設置__all__ = [](空列表)
from school.boys import *
james.say_hello() # NameError: name 'james' is not defined
包內(nèi)引用
一個模塊可以導入本包內(nèi)的模塊蚣驼,也可以從鄰包導入魄幕。導入的時候,可以使用相對位置或者絕對位置導入颖杏。需要注意的是纯陨,在主模塊中導入不論本包或者鄰包的模塊的時候,總是要使用絕對位置留储,下面通過具體的示例來說明翼抠。
############## 引用相同包中的模塊 ##############
# 在james.py中引用michael.py中定義的name
# 使用相對位置
from .michael import name as michael_name
print(michael_name)
# 使用絕對位置
from school.boys.michael import name as michael_name
################################################
############## 引用鄰包中的模塊 ################
# 在james.py中引用amanda.py中定義的name
# 使用相對位置
from ..girls.amanda import name as amanda_name
print(amanda_name)
# 使用絕對位置
from school.girls.amanda import name as amanda_name
################################################
############## 主模塊(例如把james.py作為主模塊來運行)中,必須使用絕對位置 ##############
# 例如获讳,在james.py中以相對位置導入michael.py机久,并且把james.py作為主模塊運行,會出現(xiàn)一下錯誤
# ModuleNotFoundError: No module named '__main__.michael'; '__main__' is not a package
from .michael import name as michael_name
print(michael_name)
#####################################################################################
自定義init.py
- 自動加載子模塊 - 還是以本文開始的文件結(jié)構(gòu)為例∨夂浚現(xiàn)在膘盖,我們想在導入school.boys包的時候,自動就導入james.py和michael.py這兩個模塊尤误。只需要在boys下的init.py中添加下面的代碼
# school/boys/__init__.py
from . import james
from . import michael
# 在主模塊中導入
import school.boys
school.boys.michael.say_hello()
- 合并子模塊為單一的邏輯模塊 - 例如james.py下有james_greeting方法侠畔,michael.py下有michael_greeting方法,希望在主模塊中調(diào)用的時候损晤,看起來這兩個方法屬于同一個模塊软棺,比如屬于boys這個包,這樣就不需要導入michael.py尤勋、james.py
# school/boys/__init__.py
from .james import james_greeting
from .michael import michael_greeting
# 在主模塊中導入
import school.boys
school.boys.michael_greeting()
school.boys.james_greeting()
- 包命名空間 - 文章一開始的部分就提到喘落,我們可以在一個模塊中導入一個包茵宪,一個包下面包含init.py文件。如果你好奇瘦棋,或許你已經(jīng)試過了 - 如果我們刪除了包下面的init.py稀火,我們依然可以在模塊中導入這個包,這個神奇的魔法是通過“包命名空間”實現(xiàn)赌朋。當一個文件夾下不包含init.py的時候凰狞,那么解釋器將把這個文件夾理解為包命名空間。這種用法沛慢,可能會用在一些開發(fā)框架中赡若,對于框架的使用者而言,可以創(chuàng)建相同名稱的文件夾并創(chuàng)建自己的模塊团甲,相當于把自己的模塊整合到該開發(fā)框架中逾冬。我們可以輸出某個包的str,通過判斷是否包含"namespace"來判斷是否是包命名空間躺苦。
import school.boys
print(school.boys.__path__)
print(school.boys)
# output
# 包
['D:\\Workspace\\Python\\PackageDemo\\school\\boys']
<module 'school.boys' from 'D:\\Workspace\\Python\\PackageDemo\\school\\boys\\__init__.py'>
# 包命名空間
_NamespacePath(['D:\\Workspace\\Python\\PackageDemo\\school\\boys'])
<module 'school.boys' (namespace)>
添加本地的包到項目中
有一種情況是粉渠,在公司的項目中,我們需要使用到一些自家的通用的包圾另,這個包無法通過網(wǎng)絡獲取霸株,但是在我們的開發(fā)環(huán)境中可以找到,那在我們開發(fā)的項目中集乔,如何去導入呢去件?一種簡單粗暴的方法是,將包所在的路徑添加的系統(tǒng)變量PATHONPATH中(其實還可以pip install --user packagename 來安裝私有包)扰路;另一個種是我們在項目中尤溜,修改sys.path,這樣去告訴解釋器去哪里找這個包汗唱。例如宫莱,現(xiàn)在我們把這個自家是包復制到項目是packages目錄中:
import sys
from os.path import abspath, join, dirname
sys.path.insert(0, join(abspath(dirname(__file__)), 'src'))