日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

Python回顾与整理10:模块

發布時間:2025/4/16 python 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python回顾与整理10:模块 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

? ? ? ? 模塊是用來組織Python代碼方法的方法,而包則是用來組織模塊的,充分利用好包和模塊將有利于開發出結構清晰的大型程序。




1.什么是模塊


????????所謂模塊,其實就是一個包含了特定功能代碼的.py文件,在這個.py文件中,主要有如下的代碼類型:

  • 包含數據成員和方法的類

  • 一組相關但彼此獨立的操作函數

  • 全局變量

????????使用import語句就可以導入一個模塊中的相關屬性。




2.模塊和文件


????????模塊是按照邏輯上來組織Python代碼的方法,而體現在物理層面上,它就是一個文件,因此,一個文件被看作是一個獨立模塊,一個模塊也可以被看作是一個文件。模塊的文件名就是模塊的名字加上擴展名.py。

????????與其他可以導入類的語言不同,在Python中導入的是模塊或模塊屬性。


(1)模塊名稱空間

????????名稱空間是Python非常重要的一個概念,所謂名稱空間,其實指的是一個名稱到對象的關系映射集合。可以因為每個模塊都定義了它自己的唯一的名稱空間,所以不同模塊間不會出現名稱交叉現象,通過句點屬性的訪問方式,即使兩個模塊里有相同名稱的變量,由于模塊名稱的不同,也不會發生名稱沖突。


(2)搜索路徑和路徑搜索

????????模塊的導入(使用import語句)需要一個叫做“路徑搜索”的過程,即在文件系統“預定義區域”中查找要導入的模塊文件,而這些預定義區域其實是Python搜索路徑的集合,這里需要注意下面兩個概念:

  • 路徑搜索:指查找某個文件的操作,是動詞

  • 搜索路徑:需要查找的一組目錄,是名詞

????????如果模塊名稱不在搜索路徑中,就會觸發ImportError異常:

1 2 3 4 >>>?import?mymodules Traceback?(most?recent?call?last): ??File?"<stdin>",?line?1,?in?<module> ImportError:?No?module?named?mymodules

????????而默認搜索路徑是在編譯或安裝時指定的,可以在兩個地方修改:

  • 設置環境變量PYTHONPATH

  • 在sys.path中添加搜索路徑

????????啟動Python解釋器后,搜索路徑會被保存在sys模塊的sys.path變量中:

1 2 3 >>>?import?sys >>>?sys.path ['',?'/usr/local/lib/python2.7/dist-packages/pip-8.0.2-py2.7.egg',?'/usr/local/lib/python2.7/dist-packages/setuptools-3.3-py2.7.egg',?'/usr/lib/python2.7',?'/usr/lib/python2.7/plat-x86_64-linux-gnu',?'/usr/lib/python2.7/lib-tk',?'/usr/lib/python2.7/lib-old',?'/usr/lib/python2.7/lib-dynload',?'/usr/local/lib/python2.7/dist-packages',?'/usr/lib/python2.7/dist-packages',?'/usr/lib/python2.7/dist-packages/PILcompat',?'/usr/lib/python2.7/dist-packages/gtk-2.0',?'/usr/lib/python2.7/dist-packages/ubuntu-sso-client']

????????返回的是一個列表,第一個元素表示的是當前目錄。可以通過向這個列表添加元素(使用append或insert)來增加搜索路徑:

1 2 3 4 5 6 >>>?import?my Traceback?(most?recent?call?last): ??File?"<stdin>",?line?1,?in?<module> ImportError:?No?module?named?my >>>?sys.path.append('/home/xpleaf/test') >>>?import?my

????????如果有多個相同的模塊名稱,Python解釋器會使用沿著搜索路徑順序找到的第一個模塊。

????????另外使用sys.modules可以找到當前導入了哪些模塊和它們來自什么地方,如下:

1 2 >>>?sys.modules {'copy_reg':?<module?'copy_reg'?from?'/usr/lib/python2.7/copy_reg.pyc'>,?'sre_compile':?<module?'sre_compile'?from?'/usr/lib/python2.7/sre_compile.pyc'>,...}

????????可以看到,與sys.path不同,sys.modules返回的是一個字典,其中key為模塊的名稱,鍵值為模塊的路徑。




3.名稱空間


????????名稱空間是名稱(標識符)到對象的映射,向名稱空間添加名稱的操作過程涉及綁定標識符到指定對象的操作,同時會給該對象的引用計數加1。主要有以下幾種名稱空間:

  • 內建名稱空間:由__builtins__模塊中的名字構成,Python解釋器啟動時自動加載

  • 全局名稱空間:加載完內建名稱空間后加載

  • 局部名稱空間:執行一個函數時會產生該名稱空間,函數執行結束后就會釋放

????????其中,關于__builtins__模塊和__builtin__模塊的區別,可以查看這篇博文:《Python中__builtin__和__builtins__的深入探討》

????????

(1)名稱空間與變量作用域比較

????????名稱空間是純粹意義上的名字和對象的映射關系,而作用域指出了從用戶代碼的哪些物理位置可以訪問到這些名字。其關系如下:

????????顯然就很清晰了。


(2)名稱查找、確定作用域、覆蓋

????????訪問一個屬性時,解釋器必須要在三個名稱空間中的一個找到它,首先是局部名稱空間,如果沒有找到,則查找全局名稱空間,如果還是查找失敗,就查找內建名稱空間,最后還是失敗了,就會引發NameError異常。

????????顯然上面的名稱查找過程充分地體現了作用域覆蓋的特性。


(3)無限制的名稱空間

????????可函數中,可以通過func.attribute給函數添加屬性屬性,從而創建了另外一個名稱空間,而在面向對象編程中,也可以通過類似的方式給一個實例,一個實例就是一個名稱空間:

1 2 3 4 5 6 7 8 9 10 >>>?foo?=?test() >>>?foo.name?=?'xpleaf' >>>?foo.loving?=?'cl' >>>? >>>?foo.name 'xpleaf' >>>?foo.loving 'cl' >>>?foo.__dict__ {'name':?'xpleaf',?'loving':?'cl'}




4.導入模塊


(1)import語句

????????使用import語句可以導入模塊,建議以這樣的順序導入模塊:

  • Python標準庫模塊

  • Python第三方模塊

  • 應用程序自定義模塊

????????解釋器執行import語句時,如果在搜索路徑中找到該模塊,就會進行加載,該過程遵循下面的原則:

  • 如果在一個模塊的頂層導入,它的作用域是全局的

  • 如果在函數中導入一個模塊,它的作用域是局部的

  • 如果模塊是被第一次導入,它將加載并執行

????????對于最后一點,可以驗證如下:

1 2 3 >>>?import?test Hello >>>?import?test

????????test模塊中只有一個print語句,可以看到后面再次導入時并不執行該print語句。


(2)from-import語句

????????可以使用from-import語句導入指定的模塊屬性,即把指定名稱導入到當前作用域(全局名稱空間或局部名稱空間,取決于導入的位置)中,語法如下:

1 from?module?import?name1[,?name2[,?...nameN]]

????????當然,可以多行導入:

1 2 from?flask?import?render_template,?redirect,?flash,?\ ????url_for,?request,?current_app,?jsonify

????????也可以使用from-import-as:

1 from?datetime?import?datetime?as?showtime




5.導入模塊的特性


????????當模塊被導入時,會有如下的特性:

  • 載入時執行模塊

????????加載模塊會導致這個模塊被“執行”,也就是被導入模塊的頂層代碼將直接被執行,這通常包括全局變量以及類和函數的聲明,如果有檢查__name__的操作,那么它也會被執行。

????????當然,應該把盡可能多的代碼封裝到函數,只把函數和模塊定義放入模塊的頂層是良好的模塊編程習慣。

  • 導入(import)和加載(load)

????????一個模塊只被加載(執行)一次,無論它被導入多少次。前面已經有相應的例子。

  • 導入到當前名稱空間

????????即把模塊的名稱空間導入到當前作用域(全局名稱空間或局部名稱空間,取決于導入的位置),這樣的話,如果當前作用域擁有相同名稱的變量,就會被覆蓋。

  • 關于__future__

????????可以通過下面的導入語句使用Python的一些新特性:

1 from?__future__?import?new_feature
  • 警告框架

????????需要使用到時再查看相關文檔。

  • 從ZIP文件中導入模塊

  • “新的”導入鉤子




6.模塊內建函數


????????如下:

  • __import__()

????????import語句實際上是調用了該函數,語法如下:

1 __import__(name,?globals={},?locals={},?fromlist=[],?level=-1)

? ? ????即可以這樣來導入sys模塊:

1 sys?=?__import__('sys')
  • globals()和locals()

????????使用globals()和locals()可以分別輸出包含全局名稱空間和局部名稱空間的一個字典,只是在全局名稱空間下,globals()和locals()的輸出是相等的,因為這時的局部名稱空間就是全局名稱空間。

????????一個技巧是,可以通過這兩個函數來調用全局或局部變量,在這開發中可能會用到,如下:

1 2 3 4 5 6 7 >>>?def?sayHi(name): ...?????print?'Hello,?',?name ...? >>>?globals()['sayHi'] <function?sayHi?at?0x7f56dc7bf140> >>>?globals()['sayHi']('xpleaf') Hello,??xpleaf
  • reload()

????????使用reload()可以重新加載一個已經導入的模塊,對于前面只有print語句的test模塊,測試如下:

1 2 3 4 5 6 >>>?import?test Hello >>>?import?test >>>?reload(test) Hello <module?'test'?from?'test.pyc'>

????????不過使用reload()時需要遵循下面的原則:

  • 模塊必須是全部導入,而不能是使用from-import

  • reload()的參數是模塊名字本身,而不是其字符串,即是reload(test)而不是reload('test')




  • 7.包


    ????????包是一個有層次的文件目錄結構,它定義了一個由模塊和子包組成的Python應用程序執行環境。


    (1)目錄結構

    ????????有如下的包及其結構:

    ????????在包外運行Python交互器,則下面的導入方式都是可以的:

    1 2 3 4 5 6 7 8 9 10 11 import?Phone.Mobile.Analog Phone.Mobile.Analog.dial() from?Phone?import?Mobile Mobile.Analog.dial('3245648') from?Phone.Mobile?import?Analog Analog.dial() from?Phone.Mobile.Analog?import?dial dial('3245648')

    ????????只是上面的導入方式其實都是絕對導入。


    (2)__init__.py

    ????????只要是包,都必須包含__init__.py文件,否則只是一個普通的目錄結構,而不是包,關于__init__.py,有如下特性:

    • 導入一個包,實際上是導入這個包的__init__.py文件(模塊)

    ????????對于上面的包結構,如果Phone/__init__.py的內容如下:

    1 2 packageName?=?'Phone' print?'Package?<Phone>'

    ????????則導入Phone包時輸出如下:

    1 2 >>>?import?Phone Package?<Phone>

    ????????此時只是把Phone加入到當前名稱空間中:

    1 2 >>>?dir() ['Phone',?'__builtins__',?'__doc__',?'__name__',?'__package__']

    ????????因為導入一個包實際上是導入這個包的__init__.py模塊,所以,只要不在這個模塊中的名稱空間,都無法通過Phone來訪問,即使已經導入了Phone:

    1 2 3 4 5 6 7 8 >>>?Phone.Mobile Traceback?(most?recent?call?last): ??File?"<stdin>",?line?1,?in?<module> AttributeError:?'module'?object?has?no?attribute?'Mobile' >>>?Phone.Pager Traceback?(most?recent?call?last): ??File?"<stdin>",?line?1,?in?<module> AttributeError:?'module'?object?has?no?attribute?'Pager'

    ????????因為上面的__init__.py模塊中并沒有Mobile和Pager這兩個變量,即這兩個變量不在其名稱空間中,因為__init__.py中定義了一個packageName變量,所以可以通過Phone來訪問:

    1 2 >>>?Phone.packageName 'Phone'
    • 在__init__.py中可以先導入一些模塊或子包,使得可以通過上層包訪問子包

    ????????上面的例子中,顯然不能通過Phone來訪問它的子包Mobile,現在可以在Phone/__init__.py中來先導入Phone的幾個子包:

    1 2 import?Mobile import?Pager

    ????????就可以通過Phone來訪問了:

    1 2 3 4 5 >>>?import?Phone >>>?Phone.Mobile <module?'Phone.Mobile'?from?'Phone/Mobile/__init__.pyc'> >>>?Phone.Pager <module?'Phone.Pager'?from?'Phone/Pager/__init__.pyc'>

    ????????當然,如果想要訪問子包下的模塊,也是不行的,原因是一樣的:

    1 2 3 4 >>>?Phone.Mobile.Digital Traceback?(most?recent?call?last): ??File?"<stdin>",?line?1,?in?<module> AttributeError:?'module'?object?has?no?attribute?'Digital'
    • 使用__all__變量來導入所有子包

    ????????如果需要使用from Package import *的方式來導入包下的所有模塊,則需要定義__all__變量,實際上,該語句中的*表示的即是__all__列表中所包含的包名(或模塊名)。

    ????????Phone/__init__.py內容如下:

    1 2 3 import?Mobile __all__?=?['Fax',?'Pager',?'Voicedta']

    ????????使用from Package import *語句導入:

    1 2 3 >>>?from?Phone?import?* >>>?dir() ['Fax',?'Pager',?'Voicedta',?'__builtins__',?'__doc__',?'__name__',?'__package__']

    ????????可以發現只有Fax,Pager,Voicedta這三個子包被導入了,但是Mobile這個子包并沒有被導入,那是因為它不在__all__變量所定義的列表中。


    (3)絕對導入與相對導入

    ????????使用下面的方式,都為絕對導入:

    1 2 from?Package?import?Module import?Package

    ????????這時候,解釋器會從sys.path定義的路徑中去搜索需要導入的包或模塊。當然,使用相對于當前路徑的導入式的話有時候可以加快導入速度,相對導入可以使用下面的方式:

    1 from?.[Package/Module]?import?Modulce/Variable

    ????????不過需要遵循下面的原則:

    • 必須是使用from import語句

    • from 關鍵字后面一定有句點標識.

    • 只適用在包中

    ????????這三個原則都非常重要,尤其是最后一個,如果不清楚該原則的話,會導致錯誤使用相對導入從而帶來不必要的各種糾結。

    ????????關于這一點,可以參考《Python cookbook》的相關內容:《10.3 使用相對路徑名導入包中子模塊》




    8.模塊的其他特性


    (1)自動載入的模塊

    ????????主要是__builtin__模塊,它會正常地被載入,這和__builtins__模塊相同。


    (2)阻止屬性導入

    ????????如果不想讓某個模塊屬性被"from module import *"導入,那么可以給不想導入的屬性名稱加上一個下劃線(_)。不過如果導入了整個模塊,這個隱藏數據的方法就不適用了。

    ????????manage模塊內容:

    1 2 name?=?'xpleaf' _loving?=?'cl'

    ????????舉例如下:

    1 2 3 4 5 6 7 8 9 10 11 >>>?from?manage?import?* >>>?name 'xpleaf' >>>?_loving Traceback?(most?recent?call?last): ??File?"<stdin>",?line?1,?in?<module> NameError:?name?'_loving'?is?not?defined >>>? >>>?import?manage >>>?manage._loving 'cl'


    (3)不區分大小的導入

    ????????主要取決于操作系統的文件系統是否區分大小寫。


    (4)源代碼編碼

    ????????在Python模塊文件中,默認是使用ASCII編碼,如果需要使用其他編碼方法,比如Unicode編碼,則可以在一個Python模塊文件的開頭這樣寫:

    1 2 #!/usr/bin/env?python #?-*-?coding:?UTF-8?-*-

    ????????或者:

    1 #?coding:?utf-8


    (5)導入循環

    ????????允許正確的導入循環,如果出現不能解決的導入循環問題,可以嘗試在出現導入循環的兩個模塊中的一個模塊中的import語句移到最后,或根據實際情況來進行解決。


    (6)模塊執行

    ????????可以執行一個Python模塊,參考后面的內容。




    本文轉自 xpleaf 51CTO博客,原文鏈接:http://blog.51cto.com/xpleaf/1764586,如需轉載請自行聯系原作者

    總結

    以上是生活随笔為你收集整理的Python回顾与整理10:模块的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。