天天看點

Pyhton子產品化以及包管理

文章目錄

    • 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 # 直接導入子產品就可以
           
  • 局部導入受作用域影響, 例如在函數中導入一個子產品,相當于一個普通的局部變量
    Pyhton子產品化以及包管理
注意:局部作用域中變量在全局不可見(符合向外不可見,向内可見)

總結:

  • 導入頂級子產品,其名稱會加入到本地名詞空間中, 并綁定到子產品對象
  • 導入非頂級子產品,隻将其頂級子產品名稱加入到本地名詞空間中。導入的子產品必須使用完全限定名稱來通路
  • 使用的了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檔案就是包

包和普通目錄都可以當做子產品加載

Pyhton子產品化以及包管理

包目錄中的__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

Pyhton子產品化以及包管理

其他方法參考官方文檔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)
Pyhton子產品化以及包管理