python多级目录import_你真的会用Python模块与工具包吗?
在開發過程中,我們無法把所有代碼、資源都放在同一個文件中。因此,模塊導入在編碼中是很常見的。無論是C++、Java,還是Python、Go。
可以把不同功能、不同模塊進行分離,當使用的時候,可以通過import關鍵字在一個模塊中使用另外一個模塊提供的能力,這能夠大大提升代碼的開發效率。
尤其是對于Python這種對于模塊、工具包依賴較強的編程語言,這一點更為突出。
模塊導入,這一點在Python中最為常見的東西對于很多人來說都不屑一顧,但是,你真的徹底理解Python中的import嗎?
我可以斷言,絕大多數Python開發人員只是使用,卻不知所以然。
本文,就來詳細、徹底的介紹一下Python模塊導入的使用。
模塊與工具包
模塊(modules)和工具包(packages)這2個概念首當其沖,經常被Python開發者混為一談。
雖然,二者有很多相同之處,但是還是存在一定差異。因此,要想徹底理解import,首先就需要理解模塊與工具包的異同點。
模塊
Python官網對于模塊的定義如下:
模塊具有一個包含任意Python對象的命名空間,通常用作Python代碼組織單位的對象。
實際上,一個模塊通常對應一個.py文件,模塊的真正功能是可以將其導入到其他代碼中,并重復使用,例如:
>>> import math>>> math.pi
3.141592653589793
第一行代碼,通過import把math模塊導入到代碼中,通過math.pi來調用pi這一屬性。
這里需要注意,這里寫的math.pi不僅是單純的pi,它還把math充當所有屬性保持統一的命名空間。命名空間對于保持代碼的可讀性和組織性非常有用。
你可以利用 dir來查看命名空間的內容:
>>> import math>>> dir()
['__annotations__', '__builtins__', ..., 'math']
>>> dir(math)
['__doc__', ..., 'nan', 'pi', 'pow', ...]
除了上述直接導入,我們還可以導入模塊下特定的部分:
>>> from math import pi>>> pi
3.141592653589793
>>> math.pi
NameError: name 'math' is not defined
請注意,這里對比于前一種方式已經發生了一些轉變。這里的pi是放置在全局命名空間內,而不是math的命名空間內。
包
同樣,首先看一下Python官網對工具包的定義:
一個Python模塊,可以包含子模塊或遞歸地包含子包。從技術上講,包是具有__path__屬性的Python模塊。
從定義上可以看出,包仍然是模塊。但是,它們還是有一定的區別。
從編碼上來講,Python包需要在目錄下創建一個名為__init__.py的文件。
導入模塊時,通常不會導入子模塊和子包,但是,你可以通過添加__init__.py來將需要導入的子模塊和子包囊括進去。
絕對導入與相對導入
from ... import ...這種導入當時在代碼中經常會遇到,假如,我們有如下工程:
world/│
├── africa/
│ ├── __init__.py
│ └── zimbabwe.py
│
├── europe/
│ ├── __init__.py
│ ├── greece.py
│ ├── norway.py
│ └── spain.py
│
└── __init__.py
當想要導入africa時可以這樣:
from world import africa也可以這樣:
from . import africa那么這里面的**點(.)**代表什么含義?
這里的點(.)就是一種相對導入,你可以理解為從當前包中導入africa。
相反,絕對導入語句中,需要明確命名當前包:
from world import africa在編碼過程中,你可以選擇絕對導入,也可以選擇相對導入。只不過,PEP 8風格指南中,建議使用絕對導入。
Python導入路徑
這是一個需要重點理解的問題,很多開發者從接觸Python開始就是用PyCharm,它對于導入路徑已經進行了默認的配置,因此,開發者很難遇到無法導入的問題。
但是,當切換到VS Code、Sublime這些需要較多自行配置的開發工具之后,會發現無法導入,或者因為導入工具包帶來的調用錯誤問題。
Python是如何找到它要導入的模塊和包的?
你可以試著輸出sys.path,你會發現輸出列表中主要包含如下3個部分的位置:
- 當前腳本目錄
- PYTHON_PATH環境變量
- 其他與安裝相關的目錄
通常情況下,Python將對列表進行從頭開發遍歷,從每個位置中尋找給定的模塊,直到第一個匹配為止。
由于腳本所在目錄始終被排在列表的第一位,因此,導入模塊時它會首先從當前目錄下進行尋找。
所以,一定不要把自己的代碼文件名稱與工具包重名。
例如,當前目錄有一個名為math.py的文件:
# math.pydef double(number):
return 2 * number
這時候,你導入可以按照預期工作:
>>> import math>>> math.double(3.14)
6.28
但是,它已經覆蓋了Python自帶的math標準庫。如果我們誤認為導入的是標準math模塊,去調用pi、sqrt這些方法,則會報錯:
>>> math.piTraceback (most recent call last):
File "", line 1, in
AttributeError: module 'math' has no attribute 'pi'>>> math'math' from 'math.py'>
因此,為了避免這個問題,一定小心自己開發代碼文件的命名。
創建并安裝本地工具包
在Python開發過程中,經常會用到pip安裝來自PyPI倉庫的工具包,它可以用于全局的工程項目。
除了從倉庫下載安裝工具包,還可以自行在本地創建工具包,并完成安裝。
創建本地安裝包只需要創建setup.cfg和setup.py兩個項目就行:
# setup.cfg[metadata]
name = local_structure
version = 0.1.0
[options]
packages = structure
# setup.py
import setuptools
setuptools.setup()
這里的版本名稱和版本號可以自行選擇。
然后,可以執行下方命令,把創建的安裝包安裝到本地:
$ python -m pip install -e .導入樣式
為了保持代碼的可讀性和可維護性,PEP 8提出了一些針對模塊導入的規則:
- 將導入放在文件的頂部
- 每個導入要分行
- 將導入分組:首先是標準庫導入,然后是第三方導入,最后是本地應用程序或庫導入
- 在每個組中按字母順序排序導入
- 絕對導入優先于相對導入
- 避免使用通配符導入from module import *
import sys
from typing import Dict, List
# Third party imports
import feedparser
import html2text
# Reader imports
from reader import URL
資源導入
除了模塊和工具包,代碼開發過程中,還會經常用到外部資源包,針對外部資源包的導入,可以使用importlib.resources。
它是Python 3.7中的標準模塊,使用它有2點好處:
- 使得導入方式更加一致
- 可以更輕松地訪問其他包中的資源文件
例如,
>>> from importlib import resources>>> with resources.open_text("books", "alice_in_wonderland.txt") as fid:
... alice = fid.readlines()
動態導入
Python是一門動態語言,這也是它的主要特點之一。
動態語言使得你可以在程序運行的時候做很多事情,可以添加屬性、重新定義方法、更改模塊的文檔字符串。
例如,通過修改print()函數,使它不做任何操作:
>>> print("Hello dynamic world!")Hello dynamic world!
>>> # Redefine the built-in print()
>>> print = lambda *args, **kwargs: None
>>> print("Hush, everybody!")
>>> # Nothing is printed
在上述示例中,print函數就被匿名函數重新定義了。
除了這種方法,還有更為易用的動態導入方式,就是利用importlib。
先來看一段示例,
# docreader.pyimport importlib
module_name = input("Name of module? ")
module = importlib.import_module(module_name)
print(module.__doc__)
import_module()返回可以綁定到任何變量的模塊對象。然后,您可以將該變量視為常規導入的模塊。
$ python docreader.pyName of module? math
This module is always available. It provides access to the
mathematical functions defined by the C standard.
$ python docreader.py
Name of module? csv
CSV parsing and writing.
在每種情況下,該模塊都是通過動態導入的import_module()。
周期性導入
如果兩個或者多個模塊互相導入時,就會發生周期性導入。
例如,有兩個模塊yin.py和yang.py:
# yin.pyprint(f"Hello from yin")
import yang
print(f"Goodbye from yin")
# yang.py
print(f"Hello from yang")
import yin
print(f"Goodbye from yang")
嘗試在交互式命令行下導入yin時會發生下面情況:
>>> import yinHello from yin
Hello from yang
Goodbye from yang
Goodbye from yin
有些同學會疑惑,這樣互相導入,難道不會無限循環下去嗎?
這得益于Python的模塊緩存機制,在導入yin之后,會首先把它加入到緩存中,后續再導入,會先去參考緩存區域,避免無限循環。
推薦閱讀
或許,這是最強大的一款Python GUI工具
8個小技巧教你提升Python代碼質量
5款最強且免費的Python IDE
福利
最近我花費了半個月的時間,整理了1份理論+實踐的計算機視覺入門教程,這或許是你見過最好的一份CV教程之一。獨家打造、完全免費,需要的同學可以掃碼添加我的個人微信,發送“CV”獲取~
總結
以上是生活随笔為你收集整理的python多级目录import_你真的会用Python模块与工具包吗?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 美团app怎么解锁账号
- 下一篇: python神经网络教程16_Pytho