Python中包(package)的调用方式
python 是通過module組織代碼的,每一個module就是一個python文件,但是modules是通過package來組織的。
如果我們自己寫著玩,有的時候就是一兩個Python文件在同級目錄下,但是當我們開始嘗試開發更為復雜的項目的時候,package這個概念的使用就有助于我們組織我們寫的一個個modules。
module的概念相對簡單,所以不會再多說,主要是說一下package。
Python package
package的定義很簡單,在當面目錄下有__init__.py文件的目錄即為一個package。
但是這會分為兩種情況,第一種情況是一個空的__init__.py文件,另外一個情況是寫了代碼的__init__.py文件。不管是空的還是有內容的,這個目錄都會被認為是一個package,這是一個標識。
package的初始化工作
一個package 被導入,不管在什么時候__init__.py的代碼都只會被執行一次
>>> import package hello world >>> import package >>> import package由于 package 被導入時 __init__.py 中的可執行代碼會被執行,所以小心在 package 中放置你的代碼,盡可能消除它們產生的副作用,比如把代碼盡可能的進行封裝成函數或類。
__init__.py內的導入順序
當我嘗試導入
from package import somethingimport語句會首先檢查something是不是__init__.py的變量,然后檢查是不是subpackage,再檢查是不是module,最后拋出ImportError
所以檢查順序如下:
看個例子
我們有一個如下結構的package
在a.py文件內有一個函數
def bar():print("Hello, function 'bar' from module 'a' calling")在b.py文件內有一個函數
?
def foo():print("Hello, function 'foo' from module 'b' calling")然后我們添加一個空的__init__.py 文件在simple_package里面。
我們看下,當我們import simple_package的時候到底會發生什么事情(在simple_package內激活Python shell 或者simple_package的的路徑被包含在python的sys.path或者在PYTHONPATH的環境變量中)
?
>>> import simple_package >>> >>> simple_package <module 'simple_package' from '/home/bernd/Dropbox (Bodenseo)/websites/python-course.eu/examples/simple_package/__init__.py'> >>> >>> simple_package.a Traceback (most recent call last):File "<stdin>", line 1, in <module> NameError: name 'a' is not defined >>> >>> simple_package.b Traceback (most recent call last):File "<stdin>", line 1, in <module> NameError: name 'b' is not defined我們可以看到simple_package已經被成功導入,但是a.py和b.py并沒有被導入
當然了,如果你希望使用import simple_package后自動加載a或者b 模塊,這里有兩種辦法。
第一種就是在__init__.py內導入a或者b模塊,然后保存再激活python的交互環境
?
#__init__.py import a import b當你再次嘗試import simple_package后,就可以使用simple_package.a.bar()來使用模塊a中的bar()函數了。
第二辦法就是手動導入,當你想使用模塊a中的bar()函數時,需要手動導入
?
import simple_package.a as a然后就是可以a.bar()來使用bar()函數了。
一個更復雜的例子
這是一個來自官方的例子
文件結構如下
?
sound |-- effects | |-- echo.py | |-- __init__.py | |-- reverse.py | `-- surround.py |-- filters | |-- equalizer.py | |-- __init__.py | |-- karaoke.py | `-- vocoder.py |-- formats | |-- aiffread.py | |-- aiffwrite.py | |-- auread.py | |-- auwrite.py | |-- __init__.py | |-- wavread.py | `-- wavwrite.py `-- __init__.py你可以將這個package的例子下載下來。如果直接使用import sound來導入這個package,我們可以導入package sound,但是sound的子package(effects,filters,formats)并不會被自動導入。子package不會被自動導入的原因是因為在sound目錄下的__init__.py文件并沒有任何關于導入子package的代碼。
我們來看下在sound目錄下的__init__.py的代碼
?
"""An empty sound packageThis is the sound package, providing hardly anything!"""print("sound package is getting imported!")然后我們導入sound試下
?
>>> import sound sound package is getting imported! >>> sound <module 'sound' from '/home/bernd/packages/sound/__init__.py'> >>> sound.effects Traceback (most recent call last):File "<stdin>", line 1, in <module> AttributeError: module 'sound' has no attribute 'effects'如果你想使用子package的內容,但是在父package的__init__.py的文件內并沒有導入,你需要手動導入
?
>>> import sound.effects effects package is getting imported! >>> sound.effects <module 'sound.effects' from '/home/bernd/packages/sound/effects/__init__.py'>如果你希望python幫你自動導入sound.effects你可以往sound目錄下的__init__.py文件寫入
?
"""An empty sound packageThis is the sound package, providing hardly anything!"""import sound.effects print("sound package is getting imported!")那么你下次運行的時候python就會自動幫你導入sound.effects
?
>>> import sound effects package is getting imported! sound package is getting imported!當然了,除了使用絕對路徑你可以使用相對路徑來導入sound.effects
?
"""An empty sound packageThis is the sound package, providing hardly anything!"""from . import effects print("sound package is getting imported!")這跟linux的命令行比較像,.代表當前目錄,..代表上級目錄
所以你可以在sound.effects的__init__.py文件內寫入
?
from .. import formats來導入sound.formats。
當你使用sound的時候就會發現,sound.effects和sound.formats都被導入了
?
>>> import sound formats package is getting imported! effects package is getting imported! sound package is getting imported!最后我想給你展示下,怎么從sound.effects導入sound.filters.karaoke模塊,將一下代碼加入到sound.effects的__init__.py文件中
?
"""An empty effects packageThis is the effects package, providing hardly anything!"""from .. import formats from ..filters import karaoke print("effects package is getting imported!")激活python的交互環境以后,嘗試import sound
?
>>> import sound formats package is getting imported! filters package is getting imported! Module karaoke.py has been loaded! effects package is getting imported! sound package is getting imported!現在我們可以使用karaoke的函數了
?
>>> sound.filters.karaoke.func1() Funktion func1 has been called! >>>把你的整個package都導入進來
還是用前面的例子,這一次,我會額外的加入一個叫做foobar的模塊在主目錄,你可以在這里下載例子
我們嘗試使用*來進行全部的導入
?
>>> from sound import * sound package is getting imported!我們可以看到僅僅是導入了sound這個package但是其他的內容并沒有導入。
?
>>> dir() ['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']__all__
我們可以使用__all__這個魔法變量來手動導入模塊和子package,當你定義了__all__到__init__.py文件以后,python會根據你在list內給出的元素進行逐個導入
?
__all__ = ["formats", "filters", "effects", "foobar"]所以我們可以再次導入試試
?
>>> from sound import * sound package is getting imported! formats package is getting imported! filters package is getting imported! effects package is getting imported! The module foobar is getting imported看下dir()
?
>>> dir() ['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'effects', 'filters', 'foobar', 'formats'] >>>你會發現所有模塊都已經被順利導入。
那如果我們僅僅導入sound.effectspackage內所有內容呢,會發生什么,我們import的時候到底import的是什么。
我們看下結果
?
>>> from sound.effects import * sound package is getting imported! effects package is getting imported! >>> dir() ['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__'] >>>你會發現他僅僅是導入了sound.effects這個package,跟你沒有修改sound的__init__.py之前是類似情況,僅僅是導入了這個package。
所以你也可以修改sound.effects的__init__.py文件來導入effects內的所有模塊
?
__all__ = ["echo", "surround", "reverse"]看下結果
?
>>> from sound.effects import * sound package is getting imported! effects package is getting imported! Module echo.py has been loaded! Module surround.py has been loaded! Module reverse.py has been loaded! >>> >>> dir() ['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'echo', 'reverse', 'surround'] >>>總結
作者:brakchen
鏈接:https://www.jianshu.com/p/178c26789011
來源:簡書
?
總結
以上是生活随笔為你收集整理的Python中包(package)的调用方式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python内置类型—序列
- 下一篇: Python高级编程:类和实例属性的查找