智力活动是一种生活态度 https://mountaye.github.io/blog/
.py | import 引用現成的代碼
以官網給出的文件結構為例來說明:
sound/ Top-level package __init__.py Initialize the sound package formats/ Subpackage for file format conversions __init__.py wavread.py wavwrite.py aiffread.py aiffwrite.py auread.py auwrite.py ... effects/ Subpackage for sound effects __init__.py echo.py surround.py reverse.py ... filters/ Subpackage for filters __init__.py equalizer.py vocoder.py karaoke.py ...
使用現成的python 代碼
正常的編程語言教程,教人配置完開發環境之後就應該進入正題,開始講語法了。但是咱不正常,所以先來談談怎麼用別人已經寫好的代碼。其中最簡單的,就是可以直接通過包管理程序安裝的:
pip install sound
然後想要使用某個文件中的函數,比如假裝wavwrite.py
中有個函數叫write()
,以下寫法都是可以的,注意不同import 方法對應不同的函數調用寫法:
import sound sound.formats.wavwrite.write() from sound import formats formats.wavwrite.write() from sound.formats import wavwrite wavwrite.write() from sound.formats.wavwrite import write write()
但是,不是所有的python 代碼都可以直接安裝,比如一篇論文的研究成果發表之後,處理數據的代碼也往往開源,但是這些作者基本上就只是把自己寫代碼的文件夾公開出來而已,我們把文件夾下載下來,然後直接import sound
, 會報錯,提示找不到名為sound 的庫。
python 如何讀取代碼文件
仔細想想,找不到才是正常的,之前輕輕鬆鬆的一句import sound
就解決問題,這才不簡單——不同的庫往往位於文件系統的不同位置,但我們只要寫出他們的名字就行了,不需要指定文件路徑。電腦硬盤那麼大,找到庫卻幾乎是瞬間完成的。
這是因為python 並沒有搜索整個硬盤。有一個變量,一般名為PYTHONPATH
,其變量值是一個列表,表中成員是含有python 庫文件夾的路徑。當我們在命令行輸入命令的時候,電腦會:
- 搜索當前所在的文件夾,也就是在命令行輸入
python
時終端所在的文件夾。 - 遍歷
PYTHONPATH
中的文件夾。 - python 包管理程序默認的位置,一般是
<path to python>/site-package
。
看看有沒有我們要引用的庫,找到了就引入,找不到就報錯。
上一節的錯誤中,如果我們恰好位於sound 所在的文件夾,然後運行python,此時第一條生效, import sound
不會報錯,但在其他位置就不行了。
名詞解釋:interactive, script, module, package
可執行的python 命令可以出現在以下四個地方,第一種是接受鍵盤輸入的程序,後三種都是文件:
- interactive: python交互式界面,也叫做calculator mode,也就是在命令行輸入
python
之後出現的界面。每次輸入一句,結果在命令行上顯示出來。當python 退出之後,輸入過的命令就消失了。 - script: python腳本文件,也就是在命令行輸入
python somefile.py
裡面的那個somefile.py
。 - 畢竟python 是一種很輕量化的語言,在一定程度上可以起到shell 的作用,有些命令我們並不想要用完就扔,而是保存起來以便以後重複執行,另外很多命令的組合組合成函數也可以極大地簡化工作。在這種語境之下, interactive 和script 的關係,就好像Linux 命令行和bash script 的關係一樣。
- 但同時python 又是一種功能很全面的語言,完全可以勝任複雜的面向對象編程。在這種語境之下,script 也可以用來指代main module,也就是程序執行的主文件和入口,和下面的一般的module 相區分。
- module: python模塊文件,也就是在命令行輸入
python -m another
裡面的那個another
(注意這裡不寫拓展名.py
)。按照官方文檔的說法,所有.py
文件都是module。但是實際上這句話很有誤導性,上一節的main module 和一般的module 非常不同,下一節會詳細展開講。一般提到module,都是在強調這個文件定義的變量和函數可以被其他的python 文件引用。 - package: python包,互相關聯的modules 構成的更高一級的可供引用的結構,簡單理解就是含有
__init__.py
的文件夾,但是python 並不是根據文件夾和文件之間的從屬關係來確定package 和module 之間的關係的,下一節會詳細展開講。
script vs. module
python 同時兼具腳本語言的靈活性,和各種重型語言的功能全面性。因為前者,所以它並不要求程序作者一定要在一個叫做main.py
的文件裡寫一個名叫Main
的類, 然後在裡面實現一個main()
方法。但是因為後者,沒寫不代表python 不需要知道一個複雜程序執行的起點。
這個起點就是不帶有-m
參數的python
命令後面跟著的.py
文件,這就使得這個文件變得比其他.py
文件特殊。底層表現就是python 會不管這個文件的名字叫什麼,都將它的__name__
屬性賦值為"__main__"
。這樣,即便這個文件可能是一個大型庫中間的一個模塊,運行的時候python 連它的真名都不知道,就更找不到它同級和上下級的其他模塊了。
各種普通模塊被python 用到的方法就是通過在主模塊main module(或者說script)中import。經過“python 如何讀取代碼文件”一節中的搜索過程之後找到了所需模塊或包,模塊的名字、模塊之間的關係、模塊裡定義了哪些屬性和函數,就被python 了解了,從而當主模塊召喚他們的時候就知道去哪裡找相應的代碼。除了在被import 的時候, python -m
命令的賓語也可以告訴python 被運行的模塊和包的相對關係: python -m sound.formats.wavwrite
,此時python 執行了wavwrite.py
中的所有可執行的命令,同時知道從sound/
到wavwrite.py
的各個包之間的關係。
absolute import vs. relative import
開頭使用已經安裝過的包使用的語法全都是絕對引用(absolute import),表現就是import 語句裡面沒有以.
作為開頭的。
另外一種import 方法叫相對引用(relative import), .
表示模塊所在的文件夾, ..
表示模塊的上一級文件夾。主要用在各種明確知道自己是工具代碼,而且是一個更高層次結構的組成部分,幾乎永遠不需要被作為主模塊運行的代碼。
回到開頭例子裡的文件結構,假如sound/effects/surround.py 中想要使用sound/formats/wavwrite.py 和sound/effects/echo.py 中的函數,可以寫成:
# in sound/effects/surround.py from ..formats import wavwrite from . import echo
如何組織代碼,以便自己重用
研究終於推進到了準備寫論文的階段了(學渣本質暴露了),寫草稿之餘,之前幾年時間裡做過的處理和分析,接下來的一兩個月裡需要把工作流程規範化之後迅速重做一遍確認。
隨手寫散落各處的分析代碼需要整理到一起,之前試圖統一到一個項目之下,結果總是在某個模塊引用其他模塊的時候遇到報錯。於是才有了這篇文章。
以下是這篇文章給出的一個推薦的項目文件結構:
|- notebooks/ |- 01-first-logical-notebook.ipynb |- 02-second-logical-notebook.ipynb |- prototype-notebook.ipynb |- archive/ |- no-longer-useful.ipynb |- projectname/ |- projectname/ |- __init__.py |- config.py |- data.py |- utils.py |- setup.py |- README.md |- data/ |- raw/ |- processed/ |- cleaned/ |- scripts/ |- script1.py |- script2.py |- archive/ |- no-longer-useful.py |- environment.yml
學過這篇筆記包含的內容,我才理解作者這樣的安排。既然主文件很難沒辦法通過相對引用來找到工具代碼,索性就把工具代碼寫成一個完整可安裝的庫,然後就像numpy
, pandas
一樣在獨立的notebook 和scripts 中引用。
但是要讓一個包可安裝,需要創建並編輯setup.py
這個文件。這篇文章已經夠長了,所以這個話題還是下次再說吧。
參考鏈接
- What's the difference between a Python module and a Python package? . all python files re modules, while package is a specific kind of modules. It is a subsection of module in the python documentation.
- Official explanation of python module:https://docs.python.org/3/tutorial/modules.html
- This stackoverflow answer: “run as module” is different from “run as script”. run as module sets the “name” to the module's name, while running as script sets it to
__main__
. Here we use “name” instead of__name__
because it also contains__path__
in newer versions. - A tutorial for project organization: https://realpython.com/python-application-layouts/
- Official about packaging: https://packaging.python.org/en/latest/tutorials/packaging-projects/
- Gist: How to organize data science project: https://gist.github.com/ericmjl/27e50331f24db3e8f957d1fe7bbbe510
- From the gist there is a link: http://drivendata.github.io/cookiecutter-data-science
喜歡我的文章嗎?
別忘了給點支持與讚賞,讓我知道創作的路上有你陪伴。
發布評論…