天天看點

python基礎---子產品與包

1、子產品導入方法

常見的場景:

一個子產品就是一個包含了python定義和聲明的檔案,檔案名就是子產品名字加上.py的字尾,導入子產品可以實作功能的重複利用

import加載的子產品分為四個通用類别: 

1 使用python編寫的代碼(.py檔案)

2 已被編譯為共享庫或DLL的C或C++擴充

3 包好一組子產品的包

4 使用C編寫并連結到python解釋器的内置子產品

a. import語句

python 内置了很多子產品,比如os、sys、time等,也可以是自定義子產品、子產品包、C擴充等,使用import無法區分導入的子產品類型

import 子產品名      

例如:導入spam.py

import spam(不含.py)

導入多個子產品:

import os,time,sys

子產品可以包含可執行的語句和函數的定義,這些語句的目的是初始化子產品,它們隻在子產品名第一次遇到導入import語句時才執行(import語句是可以在程式中的任意位置使用的,且針對同一個子產品import很多次,為了防止你重複導入,python的優化手段是:第一次導入後就将子產品名加載到記憶體了,後續的import語句僅是對已經加載大記憶體中的子產品對象增加了一次引用,不會重新執行子產品内的語句)

每個子產品都是一個獨立的名稱空間,定義在這個子產品中的函數,把這個子產品的名稱空間當做全局名稱空間,這樣我們在編寫自己的子產品時,就不用擔心我們定義在自己子產品中全局變量會在被導入時,與使用者的全局變量沖突

導入子產品幹了哪些事:

1 執行源檔案

2 以一個源檔案的全局名稱空間

3 在目前位置拿到一個子產品名,指向2建立的名稱空間

<code>#測試一:money與spam.money不沖突</code>

<code>#test.py</code>

<code>import</code> <code>spam</code>

<code>money</code><code>=</code><code>10</code>

<code>print</code><code>(spam.money)</code>

<code>輸出:</code>

<code>from</code> <code>the spam.py</code>

<code>1000</code>

<code> </code> 

<code>#測試二:read1與spam.read1不沖突</code>

<code>def</code> <code>read1():</code>

<code>     </code><code>print</code><code>(</code><code>'========'</code><code>)</code>

<code>spam.read1()</code>

<code>輸出:</code>

<code>spam</code><code>-</code><code>&gt;read1</code><code>-</code><code>&gt;money1000</code>

<code>#測試三:執行spam.change()操作的全局變量money仍然是spam中的</code>

<code>money</code><code>=</code><code>1</code>

<code>spam.change()</code>

<code>print</code><code>(money)</code>

<code>1</code>

子產品别名功能

練習:

有兩鐘sql子產品mysql和oracle,根據使用者的輸入,選擇不同的sql功能

<code>#mysql.py</code>

<code>def</code> <code>sqlparse():</code>

<code>    </code><code>print</code><code>(</code><code>'from mysql sqlparse'</code><code>)</code>

<code>#oracle.py</code>

<code>    </code><code>print</code><code>(</code><code>'from oracle sqlparse'</code><code>)</code>

<code>db_type</code><code>=</code><code>input</code><code>(</code><code>'&gt;&gt;: '</code><code>)</code>

<code>if</code> <code>db_type </code><code>=</code><code>=</code> <code>'mysql'</code><code>:</code>

<code>    </code><code>import</code> <code>mysql as db</code>

<code>elif</code> <code>db_type </code><code>=</code><code>=</code> <code>'oracle'</code><code>:</code>

<code>    </code><code>import</code> <code>oracle as db</code>

<code>db.sqlparse()</code>

        為已經導入的子產品起别名的方式對編寫可擴充的代碼很有用,假設有兩個子產品xmlreader.py和csvreader.py,它們都定義了函數read_data(filename):用來從檔案中讀取一些資料,但采用不同的輸入格式。可以編寫代碼來選擇性地挑選讀取子產品

<code>if</code> <code>file_format </code><code>=</code><code>=</code> <code>'xml'</code><code>:</code>

<code>    </code><code>import</code> <code>xmlreader asreader</code>

<code>elif</code> <code>file_format </code><code>=</code><code>=</code> <code>'csv'</code><code>:</code>

<code>    </code><code>import</code> <code>csvreader asreader</code>

<code>data</code><code>=</code><code>reader.read_date(filename)</code>

b. from…import語句

from 子產品名  import 子產品名中的方法

例如:from spamimport money,read1,read2,change

如果子產品中的方法太多,可以使用:

from spam import  *     (不推薦使用,容易與執行檔案的命名空間沖突)

__all__=['money','x']      #對from spam import * 有用,之後導入money、x方法

_money=1000             #對from spam import * 有用,不會導入這個方法

對比import spam,會将源檔案的名稱空間'spam'帶到目前名稱空間中,使用時必須是spam.名字的方式,而from 語句相當于import,也會建立新的名稱空間,但是将spam中的名字直接導入到目前的名稱空間中,在目前名稱空間中,直接使用名字就可以了

<code>#spam.py</code>

<code>print</code><code>(</code><code>'from the spam.py'</code><code>)</code>

<code>money</code><code>=</code><code>0</code>

<code>    </code><code>print</code><code>(</code><code>'spam-&gt;read1-&gt;money'</code><code>,money)</code>

<code>def</code> <code>read2():</code>

<code>    </code><code>print</code><code>(</code><code>'spam-&gt;read2 calling read'</code><code>)</code>

<code>    </code><code>read1()</code>

<code>def</code> <code>change():</code>

<code>    </code><code>global</code> <code>money</code>

<code>    </code><code>money</code><code>=</code><code>0</code> 

<code># 執行檔案</code>

<code>from</code> <code>spam </code><code>import</code> <code>money,read1,read2,change</code>

<code>print</code><code>(read1)</code>

<code>from</code> <code>the spam.py                    </code><code>#首先執行spam.py</code>

<code>0</code>                      <code>#仍然是目前執行檔案的命名空間中的money</code>

<code>&lt;function read1 at </code><code>0x00000000026DE950</code><code>&gt;</code>

優點:使用源檔案内的名字時無需加字首,使用友善

缺點:容易與目前檔案的名稱空間内的名字混淆

c. 子產品搜尋路徑

子產品隻在第一次導入時才會執行,之後的導入都是直接引用記憶體已經存在的結果

import sys

print('spam' in sys.modules)            #存放的是已經加載到内的子產品

注意:自定義的子產品名一定不要與python自帶的子產品名重名

子產品的查找順序是:記憶體中已經加載的子產品-&gt;内置子產品-&gt;sys.path路徑中包含的子產品

<code>import</code> <code>time</code>

<code>import</code> <code>importlib</code>

<code>import</code> <code>spam           </code><code>#導入子產品會把硬碟中的子產品内容加載到記憶體中</code>

<code>time.sleep(</code><code>20</code><code>)</code>

<code>import</code> <code>spam           </code><code>#再次導入會直接從記憶體中查找,忽略硬碟中子產品内容</code>

<code>importlib.</code><code>reload</code><code>(spam)         </code><code>#會重新加載子產品(隻在測試環境使用)</code>

print(sys.path)              #子產品的搜尋路徑

sys.path從以下位置初始化

    1  執行檔案所在的目前目錄

    2  PTYHONPATH(包含一系列目錄名,與shell變量PATH文法一樣)

    3  依賴安裝時預設指定的

加入子產品路徑:

<code>import</code> <code>sys</code>

<code>print</code><code>(sys.path)</code>

<code>sys.path.insert(</code><code>0</code><code>,r</code><code>'要添加的子產品路徑'</code><code>)       </code><code>#插入子產品路徑</code>

<code>sys.path.append(r</code><code>'要添加的子產品路徑'</code><code>)         </code><code>#追加子產品路徑</code>

d. 區分python檔案的兩種用途

檔案當做腳本(執行檔案)運作時__name__等于__main__

檔案當做子產品被加載運作時__name__等于子產品名

<code># m1.py</code>

<code>import</code> <code>os,sys</code>

<code>x</code><code>=</code><code>1</code>

<code>def</code> <code>func1():</code>

<code>    </code><code>print</code><code>(</code><code>'from m1'</code><code>)</code>

<code>def</code> <code>func2():</code>

<code>    </code><code>print</code><code>(</code><code>'from m2'</code><code>)</code>

<code>def</code> <code>func3():</code>

<code>    </code><code>print</code><code>(</code><code>'from m3'</code><code>)</code>

<code># print(__name__)</code>

<code>#檔案當做腳本運作時__name__等于__main__</code>

<code>#檔案當做子產品被加載運作時__name__等于子產品名</code>

<code>if</code> <code>__name__ </code><code>=</code><code>=</code> <code>'__main__'</code><code>:</code>

<code>    </code><code>#當做腳本使用時才執行</code>

<code>    </code><code>func1()</code>

<code>    </code><code>func2()</code>

<code>    </code><code>func3() </code>

<code># run.py</code>

<code>import</code> <code>m1            </code><code>#導入m1子產品</code>

<code>m1.func3()</code>

e. 包

python3中建立檔案夾會自動建立__init__.py

python2中建立包需要手動建立__init__.py

1. 無論是import形式還是from...import形式,凡是在導入語句中(而不是在使用時)遇到帶點的,都要第一時間提高警覺:這是關于包才有的導入文法

2. 包是目錄級的(檔案夾級),檔案夾是用來組成py檔案(包的本質就是一個包含__init__.py檔案的目錄)

3. import導入檔案時,産生名稱空間中的名字來源于檔案,import 包,産生的名稱空間的名字同樣來源于檔案,即包下的__init__.py,導入包本質就是在導入該檔案

強調:

 1. 在python3中,即使包下沒有__init__.py檔案,import 包仍然不會報錯,而在python2中,包下一定要有該檔案,否則import 包報錯

 2. 建立包的目的不是為了運作,而是被導入使用,記住,包隻是子產品的一種形式而已,包即子產品

    3.凡是在導入時帶點的,點的左邊都必須是一個包

本文轉自lyndon部落格51CTO部落格,原文連結http://blog.51cto.com/lyndon/1953171如需轉載請自行聯系原作者

遲到的棟子