文章目錄
-
- 1.子產品化
- 2.導入語句
-
- 2.1 import
- 2.2 from ... import ...
- 2.3子產品命名規範:
- 2.4子產品搜尋順序
-
- 2.4.1 sys.path - 檢視python子產品的路徑搜尋順序:
- 2.4.2 sys.modules - 檢視子產品加載記錄:
- 3.子產品運作
-
- 3.1子產品的屬性:
- 4.包
-
- 4.1子產品和包的總結:
- 4.1 子目錄
- 4.2相對導入和絕對導入(這裡有大坑!!!)
- 4.3包管理工具pkgutil
- 5.通路控制
-
- 子產品變量的修改
- 6.包管理
-
- 6.1為什麼使用包管理
- 6.2主要工具
-
- distuil
- setuptools
- pip
- wheel
- 6.3 使用setup.py打包
-
- 6.3.1指令
1.子產品化
程式設計語言中,庫、包、子產品是用一種概念,是代碼組織方式
Python隻有一種子產品對象類型,為了子產品化組織子產品的便利,提供了"包"的概念
子產品module,指的是python的源代碼檔案
包package,指的是子產品組織在一起的和包名同名的目錄及其相關檔案
2.導入語句
2.1 import
- import語句後面隻能寫到子產品為止
In [1]: import functools.WRAPPER_UPDATES # import不能直接導入子產品的屬性
Traceback (most recent call last):
File "<ipython-input-1-c5aad56d0707>", line 1, in <module>
import functools.WRAPPER_UPDATES
ModuleNotFoundError: No module named 'functools.WRAPPER_UPDATES'; 'functools' is not a package
In [2]: import functools # 直接導入子產品就可以
- 局部導入受作用域影響, 例如在函數中導入一個子產品,相當于一個普通的局部變量
注意:局部作用域中變量在全局不可見(符合向外不可見,向内可見)
總結:
- 導入頂級子產品,其名稱會加入到本地名詞空間中, 并綁定到子產品對象
- 導入非頂級子產品,隻将其頂級子產品名稱加入到本地名詞空間中。導入的子產品必須使用完全限定名稱來通路
- 使用的了as,本地隻綁定as之後的名稱,指代導入的全長限定名子產品
In [1]: import os.path # 相當于導入了os和os.path,但是本地限定名隻能看到頂級子產品os
In [2]: os.curdir # 因為導入了os子產品,是以os.curdir也可以用
Out[2]: '.'
In [3]: dir() # 檢視本地變量
Out[3]:
['In',
'Out',
'_',
'_2',
'__',
'___',
'__builtin__',
'__builtins__',
'__doc__',
'__loader__',
'__name__',
'__package__',
'__spec__',
'_dh',
'_i',
'_i1',
'_i2',
'_i3',
'_ih',
'_ii',
'_iii',
'_oh',
'exit',
'get_ipython',
'os',
'quit']
2.2 from … import …
總結:
- from語句後面隻能寫到子產品為止,但是後面的import可以導入到子產品屬性
- from語句後面指定的子產品,隻會加載不會導入,是以不可調用
- import * 表示在目前名詞空間導入該子產品所有公共成員(非下劃線開頭成員)或者指定成員
下面示範幾個栗子:
In [1]: from functools import update_wrapper # 隻導入了update_wrapper方法
In [2]: functools.wraps
Traceback (most recent call last):
File "<ipython-input-2-564d19946aba>", line 1, in <module>
functools.wraps
NameError: name 'functools' is not defined
注意子產品不會被重複導入!
2.3子產品命名規範:
1.子產品就是檔案名
2.子產品必須符合辨別符的要求,字母數字下劃線,而且不能以數組開頭
3.不要使用系統名,除非你明确知道這個子產品的用處
4.通常檔案名為全小寫, 下劃線來分割
子產品是全局變量的邊界,全局變量不可以跨越子產品
2.4子產品搜尋順序
2.4.1 sys.path - 檢視python子產品的路徑搜尋順序:
傳回值為清單
從上面路徑中依次查找,并不搜尋這些路徑的子目錄
搜尋不到就會抛異常
路徑可以是字典、zip檔案、egg檔案
In [1]: import sys
In [2]: sys.path
Out[2]:
['C:\\Users\\admin',
'C:\\ProgramData\\Anaconda3\\python37.zip',
'C:\\ProgramData\\Anaconda3\\DLLs',
'C:\\ProgramData\\Anaconda3\\lib',
'C:\\ProgramData\\Anaconda3',
'',
'C:\\ProgramData\\Anaconda3\\lib\\site-packages',
'C:\\ProgramData\\Anaconda3\\lib\\site-packages\\win32',
'C:\\ProgramData\\Anaconda3\\lib\\site-packages\\win32\\lib',
'C:\\ProgramData\\Anaconda3\\lib\\site-packages\\Pythonwin',
'C:\\ProgramData\\Anaconda3\\lib\\site-packages\\IPython\\extensions',
'C:\\Users\\admin\\.ipython']
路徑順序:
- 程式主目錄,運作的主腳本所在的目錄
- Python目錄,在環境變量中設定的包路徑
- 标準庫目錄,python自帶的庫所在目錄
2.4.2 sys.modules - 檢視子產品加載記錄:
所有加載的子產品都會記錄在sys.modules中,sys.modules是存儲已經加載過得所有子產品的字典
通常情況下,解釋器會先加載一部分常用的子產品到這個字典中,每次加載一個子產品前,都會現在這個字典中檢視是否已經加載,是以不會出現子產品重複加載的情況
3.子產品運作
當标準輸入(指令行方式敲代碼)、腳本或者互動式讀取的時候,會将子產品的__name__設定為"main",子產品的頂層代碼在__main__這個作用域中才會執行。
頂層代碼:子產品中縮進最外層的代碼
如果是import導入的子產品,該子產品的__name__預設就是子產品名
# t1.py
if __name__ == "__main__":
print("in __main__")
else:
print("in module")
# t2.py
import t1 ## in module
if name == "main"的用途:
1.本子產品的功能測試
2.避免主子產品變更的副作用
3.1子產品的屬性:
屬性 | 含義 |
---|---|
__file__ | 字元串,原檔案路徑 |
__cached__ | 字元串, 編譯後的位元組碼檔案路徑,pyc檔案路徑 |
__spec__ | 顯示子產品的規範 |
__name__ | 子產品的name |
__package__ | 當子產品是包,__package__同__name__,否則可以設定頂級子產品的空字元串 |
4.包
目錄裡面包含__init__.py檔案就是包
包和普通目錄都可以當做子產品加載
包目錄中的__init__.py檔案,是在包第一次導入的時候就會執行,内容可以為空
也可以用于該包初始化工作的代碼
4.1子產品和包的總結:
- 1.子產品也是封裝,如同類、函數,他能夠封裝變量、類、函數
- 2.子產品就是命名空間,其内部的辨別符就是它的屬性,可以通過__dict__或者dir(module)檢視
- 3.包也是子產品,但是子產品不一定是包,包是特殊的子產品,是一種組織方式,包含__path__屬性
4.1 子目錄
m
|-- __init__.py
|-- m1.py
|-- m2
|-- __init__.py
|-- m21
|-- __init__.py
|-- m22.py
4.2相對導入和絕對導入(這裡有大坑!!!)
1.絕對導入
import沒有相對導入
頂層子產品使用絕對導入
2.相對導入
相對導入在包内使用,且隻能用在from語句中
具體用法:
.表示引用的子產品或包位于目前位置相同的目錄中
…表示他在目前位置的父目錄中
…表示他在目前位置的祖父目錄中
這就是大坑!!:
在一個含有相對導入的子產品中進行測試,一直在報錯,後來找了下資料才發現:使用相對導入的py檔案不能作為主子產品使用,也就是不能直接運作!!也就是不可以直接讓解釋器執行,因為相對引用就是利用__name__進行定位,作為主程式被執行時,__name__為__main__
如果檔案時__main__(也就是說不包含任何package資訊),那麼相對引用就會被解析成toplevelmodule,而不關注這個module是否存在于檔案系統中
4.3包管理工具pkgutil
從包中擷取資源:pkgutil.get_data(package, resource)
其中package為包名,resource為資源名
注意讀取的為二進制,需要decode
其他方法參考官方文檔pkgutil — Package extension utility
5.通路控制
from a import *:
- 如果a沒有__all__,隻導入共有屬性(除了_開頭的屬性)
- 如果有__all__,隻導入__all__=[ ] 清單内的屬性
-
如果__all__中定義了未知變量,導入時會AttributeError
編寫子產品中,應該盡量加入__all__
子產品變量的修改
# xyz.py
print(__name__)
X = 10
# test2.py
import xyz
print(xyz.X)
# test.py
import xyz
print(xyz.X)
xyz.X = 50 # 将xyz.X修改成50
import test2 # xyz.X = 50
- 子產品變量是同一個,是以子產品的變量也是同一個,對子產品變量的修改,會影響所有者使用
- 除非萬不得已,或者明确知道做什麼,否則不要修改子產品的變量
- 前面學過的猴子更新檔,也可以聽過更新檔覆寫的方式修改子產品的變量,類,函數等内容
6.包管理
6.1為什麼使用包管理
Python的子產品或者源檔案直接可以複制到目标項目目錄中,就可以導入使用了。
但是為了更多項目排程使用,或者共享給比人,就需要打包,或釋出到網絡,為了更好的複用。
Pypi(Python Packsge Index), 公共的子產品存儲中心,https://pypi.org/
6.2主要工具
distuil
官方庫distutils,使用安裝腳本setup.py 來建構、安裝包。
從1998年就是标準庫的一部分,直到2000年停止開發
setuptools
它是替代distutils的增強版工具集,包含easy_install工具,使用ez_setup.py檔案。支援egg格式的建構和安裝。
提供查詢、下載下傳、安裝、建構、釋出、管理等包管理功能。
setuptools是包管理的核心子產品
pip
pip目前包管理的事實标準。
建構在setuptools之上,替代easy_install的。同樣提供豐富的包管理功能。 Python3.4之前,需要單獨安裝,從Python3.4開始直接包含在安裝檔案中。
wheel
wheel格式定義在PEP427中。
wheel檔案中不包含.pyc檔案。
提供 bdist_wheel作為setuptools的擴充指令,這個指令可以用來生成新打包格式 wheel。
pip 從1.4版本開始提供了一個 wheel 子指令來安裝 wheel 包。當然,需要先安裝 wheel 子產品。
它可以讓Python庫以二進制形式安裝,而不需要在本地編譯。
6.3 使用setup.py打包
setup.py建立一個源代碼分發包的例子,參考官方文檔
Writing the Setup Script
#!/usr/bin/env python
from distutils.core import setup
setup(name='Distutils',
version='1.0',
description='Python Distribution Utilities',
author='Greg Ward',
author_email='[email protected]',
url='https://www.python.org/sigs/distutils-sig/',
packages=['distutils', 'distutils.command'],
)
6.3.1指令
- 項目根目錄下建立setup.py,就是在project下建立.注意setup檔案中的内容,特别是packages裡面的内容指定哪一個檔案就操作相應的檔案
-
setup.py build
在項目目錄下建立build/lib的下面建立子產品m的目錄
注意檢視是不是所有包m的所有目錄都複制了
-
setup.py install
相當于先執行build,再執行install
包被複制到sit-package檔案夾下
-
setup.py sdist
建立源代碼的分發包,在sdist目錄下,是一個壓縮包
-
setup.py bdist
二進制分發包,或稱作安裝程式
可以生成目标系統的操作程式
- setup.py bdist_wininst生成exe檔案
- setup.py bdist_msi 生成msi檔案
- setup.py bdist_egg 生成egg檔案
- setup.py bdist_wheel 生成whl檔案
- setup.py bdist --format=(rpm,zip,gztar,msi)