學習粗淺的python import技巧

吳建興
10 min readFeb 17, 2019

--

ABSTRACT

很慚愧的,之前我除了使用pip下載模組以外,不知道怎麼從其他地方import模組進來。目前因為研究室要嘗試用一個舊版的angr模組,沒辦法使用pip直接下載,必須從github上下載後,再checkout到舊版。所以才想要開始學習python是如何import模組的,順便寫一些學習過程中看到的東西當作紀錄,來輔助我軟爛不勘的記憶能力,如果內容有錯麻煩來糾正我一下吧!

Module & Package

sample_package/                #a package
├── __init__.py
├── sample_module.py #a module
└── sample_module_import.py #a module

Module

Package內的一個檔案。

Package

通常會是一個目錄,而該目錄底下會有一個__init__.py檔案。__init__.py檔案的用途可以參考REFERENCE[16],[17],[18],[19]。

Import

import可以作用的東西:

  1. module(.py檔)
  2. package
  3. 內建module
  4. c或c++擴展

Package內互相引用

這裡在REFERENCE[3]已經有很詳細的敘述了,寫得很好,誠心建議有興趣可以看一下,甚至還有sample code在github上!!

Absolute Import

用絕對路徑引用module,缺點是會把package名稱寫死,以後會不好改動名稱。

Relative Import

用相對路徑引用module。

Absolute Import v.s. Relative Import

test_package/
├── __init__.py
├── module1.py
├── subpackage1
│ ├── __init__.py
│ ├── module2.py
│ └── module3.py
├── subpackage2
│ ├── __init__.py
└── └── module4.py
----------------------------------------
#假設我們現在的位置在test_package/subpackage1/module2.py
#想import在同一個subpackage下的module3.py
(absolute)from test_package.subpackage1 import module3
(relative)from . import module3
#想import在不同subpackage下的module4.py
(absolute)from test_package.subpackage2 import module4
(relative)from ..subpackage2 import module4
#想import在test_package下的module1.py
(absolute)from test_package import module1
(relative)from .. import module1
#想import在同一個subpackage下的module3.py的function mod3
(absolute)from test_package.subpackage1.module3 import mod3
(relative)from .module3 import mod3

外部引用Package--試著自己做一個簡單的Package

在shell輸入下面的指令,可以看到一連串像路徑的陣列,我是選擇在/home/[username]/anaconda3/lib/python3.7/site-packages這個資料夾裡面新增一個資料夾test_package

python3
>>import sys
>>sys.path
['', '/home/[username]/anaconda3/lib/python37.zip', '/home/[username]/anaconda3/lib/python3.7', '/home/[username]/anaconda3/lib/python3.7/lib-dynload', '/home/[username]/anaconda3/lib/python3.7/site-packages', '/home/[username]/anaconda3/lib/python3.7/site-packages/firstblood-0.0.1-py3.7.egg']

假設目前的目錄長的是像下面這樣。

test_package/                   #a package
├── __init__.py
└── hi.py #a module

__init__.py可以是空的,hi.py 裡面可以寫一些簡單的function,像是下面這樣短短幾行。

#hi.py
def hello():
print("hello!")

這樣就可以使用這個超小型的package了!

python3                              #進入python3的指令介面
>>from test_package.hi import hello #從test_package這個package裡面的hi這個module拿出hello這個function
>>hello()
hello!
>>from test_package import hi #從test_package這個package裡面import hi這個module
>>hi.hello()
hello!
注意,下面兩個例子要先from test_package import hi才會成功
>>import test_package #直接import這個package
>>test_package.hi.hello()
hello!
>>import test_package as hihi #怕跟其他package或module撞名還可以用as改成自己喜歡的名稱
>>hihi.hi.hello()
hello!

TERM

[1]PEP

可以看REFERENCE[5],[6]。

PEP的全名是Python Enhancement Proposal.是一個設計的文件,提供給社群或是所有使用python的人有一個指導原則。當為python設計一個新的功能或特色的時候,PEP需要提供一個可以遵從的標準。

每個PEP都會有一個不會重複的編號,例如,PEP 1的內容就是介紹PEP本身。

[2]python path

在shell裡面進到python的cli,import sys,並且sys.path,就可以看到目前python可以從哪些路徑import module。

python3
>>import sys
>>sys.path

[3]__init__.py

詳情可以看看REFERENCE[16],[17],[18],[19]。

告知Python,擁有這個檔案的目錄要把它當作一個package來看待。__init__.py可以是空白的,也可以在裡面進行一些初始化,設定變數的動作。

REFERENCE

[1]packyou https://github.com/llazzaro/packyou

[2]PEP 328 https://www.python.org/dev/peps/pep-0328/#guido-s-decision

[3]Python 的 Import 陷阱 https://medium.com/pyladies-taiwan/python-%E7%9A%84-import-%E9%99%B7%E9%98%B1-3538e74f57e3

[4]Python 的 Import 陷阱-example code https://github.com/pyliaorachel/python-import-traps

[5]Python 101: All about imports https://www.blog.pythonlibrary.org/2016/03/01/python-101-all-about-imports/

[6]PEP 1-PEP Purpose and Guidelines https://www.python.org/dev/peps/pep-0001/#what-is-a-pep

[7] Python PEP 是什麼 ? https://www.arthurtoday.com/2009/11/python-pep.html

[8]Python Modules and Packages — An Introduction https://realpython.com/python-modules-packages/#python-packages

[9]Python Tutorial 第二堂(3)函式、模組、類別與套件 http://www.codedata.com.tw/python/python-tutorial-the-2nd-class-3-function-module-class-package

[10]import雜談之一 — — — import路徑的相對論 https://ithelp.ithome.com.tw/articles/10195501

[11]import雜談之二 — — — export機制以及namespace package https://ithelp.ithome.com.tw/articles/10196775

[12]import雜談之三 — — — sys.path的洪荒之時 https://ithelp.ithome.com.tw/articles/10196901

[13]import雜談之四 — — — 來trace一下site模組 https://ithelp.ithome.com.tw/articles/10196941

[14]import雜談之五 — — — 淺談import_hook(真的很淺) https://ithelp.ithome.com.tw/articles/10197127

[15]The import system https://docs.python.org/3/reference/import.html

[16]Python — __init__.py作用詳解 https://www.cnblogs.com/Lands-ljk/p/5880483.html

[17]What is __init__.py for https://stackoverflow.com/questions/448271/what-is-init-py-for

[18]python doc about module https://docs.python.org/3/tutorial/modules.html#packages

[19]模組 https://kaochenlong.com/2011/10/13/python-module/

NOTES

[1]在測試relative import的時候,不能直接用python執行module2,而是要在python3的cli來引入module2

QUESTION

[1]我平常使用angr的時候,都是直接import angr,這是import整個package嗎?因為angr這個資料夾裡面沒有一個叫做angr.py的檔案。

A:是import整個package沒錯

[2]假如想要用一個package,就一定要把這個package放在PYTHONPATH所指定的地方?這樣不會讓那個資料夾過於肥大嗎?

A:目前我看到的方法都是要把package丟進sys.path所指向的地方,不然就是要臨時增加路徑。

To Do List & Future Work

[1]外部引用Package那邊有一個例子,為什麼要先from test_package import hi才跑得起來呢?有興趣的話可以再翻一下官方文件。

--

--

吳建興
吳建興

Written by 吳建興

I want to be a good programmer.(´・ω・`)

No responses yet