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

歡迎訪問 生活随笔!

生活随笔

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

python

python包实际怎么使用_Python--模块与包

發布時間:2023/12/4 python 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python包实际怎么使用_Python--模块与包 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

模塊

1、什么是模塊?

一個模塊就是一個Python文件,文件名就是模塊名字加上.py后綴。因此模塊名稱也必須符合變量名的命名規范。

1 使用python編寫的代碼(.py文件)

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

3 包好一組模塊的包

4 使用C編寫并鏈接到python解釋器的內置模塊

2、為什么要使用模塊?

如果你退出python解釋器然后重新進入,那么你之前定義的函數或者變量都將丟失,因此我們通常將程序寫到文件中以便永久保存下來,需要時就通過python test.py方式去執行,此時test.py被稱為腳本script。

隨著程序的發展,功能越來越多,為了方便管理,我們通常將程序分成一個個的文件,這樣做程序的結構更清晰,方便管理。這時我們不僅僅可以把這些文件當做腳本去執行,還可以把他們當做模塊來導入到其他的模塊中,實現了功能的重復利用,

3、如何使用模塊?

方式一:import

方式二:from ... import ...

import

首先,自定義一個模塊my_module.py,文件名my_module.py,模塊名my_module

name = "我是自定義模塊的內容..."

deffunc():print("my_module:", name)print("模塊中打印的內容...")

my_module

在import一個模塊的過程中,發生了哪些事情?

#用import導入my_module模塊

importmy_module>>>模塊中打印的內容...#怎么回事,竟然執行了my_module模塊中的print語句

importmy_moduleimportmy_moduleimportmy_moduleimportmy_moduleimportmy_module>>>模塊中打印的內容...#只打印一次

從上面的結果可以看出,import一個模塊的時候相當于執行了這個模塊,而且一個模塊是不會重復被導入的,只會導入一次(python解釋器第一次就把模塊名加載到內存中,之后的import都只是在對應的內存空間中尋找。)成功導入一個模塊后,被導入模塊與文本之間的命名空間的問題,就成為接下來要搞清楚的概念了。

被導入模塊與本文件之間命名空間的關系?

假設當前文件也有一個變量為: name = 'local file', 也有一個同名的func方法。

#本地文件

name = "local file"

deffunc():print(name)#本地文件有跟被導入模塊同名的變量和函數,究竟用到的是哪個呢?

importmy_moduleprint(my_module.name) #根據結果可以看出,引用的是模塊里面的name

my_module.func() #執行的是模塊里面的func()函數

>>>模塊中打印的內容...

我是自定義模塊的內容...

my_module: 我是自定義模塊的內容...print(name) #使用的是本地的name變量

func() #使用的是本地的func函數

>>>local file

local file

在import模塊的時候發生了下面的幾步:

1、先尋找模塊

2、如果找到了,就在內存中開辟一塊空間,從上至下執行這個模塊

3、把這個模塊中用到的對象都收錄到新開辟的內存空間中

4、給這個內存空間創建一個變量指向這個空間,用來引用其內容。

總之,模塊與文件之間的內存空間始終是隔離的

給導入的模塊取別名,用as關鍵字

如果導入的模塊名太長不好記,那么可以通過“import 模塊名 as? 別名”的方式給模塊名取一個別名,但此時原來的模塊就不再生效了(相當于創建了新的變量名指向模塊內存空間,斷掉原模塊名的引用)。

#給my_module模塊取別名

importmy_module as smprint(sm.name)>>>我是自定義模塊的內容...print(my_module.name) #取了別名后,原來的模塊名就不生效了

>>>NameError: name'my_module' is not defined

給模塊去別名,還可以使代碼更加靈活,減少冗余,常用在根據用戶輸入的不同,調用不同的模塊。

#按照先前的做法,寫一個函數,根據用戶傳入的序列化模塊,使用對應的方法

defdump(method):if method == 'json':importjson

with open('dump.txt', 'wb') as f:

json.dump('xxx', f)elif method == 'pickle':importpickle

with open('dump.txt', 'wb') as f:

pickle.dump('xxx', f)#上面的代碼冗余度很高,如果簡化代碼?通過模塊取別名的方式,可以減少冗余

defdump(method):if method == 'json':importjson as melif method == 'pickle':importpickle as m

with open('dump.txt', 'wb') as f:

m.dump('dump.txt', f)

如何同時導入多個模塊?

方式一:每行導入一個模塊

importosimportsysimport time

方式二:一行導入多個模塊,模塊之間通過逗號“,”來分隔

import os, sys, my_module

但是,根據PEP8規范規定使用第一種方式,并且三種模塊有先后順序(內置>第三方>自定義)

#根據PEP8規范

importosimportdjangoimport my_module

模塊搜索路徑

通過sys內置模塊,我們知道sys.path存儲了所有模塊的路徑,但是正常的sys.path的路徑中除了內置模塊,第三方模塊所在的路徑之外,只有一個路徑是永遠正確的,就是當前執行的文件所在目錄。一個模塊是否能夠被導入,就取決于這個模塊所在的目錄是否在sys.path中。

python解釋器在啟動時會自動加載一些模塊,可以使用sys.modules查看

在第一次導入某個模塊時(比如my_module),會先檢查該模塊是否已經被加載到內存中(當前執行文件的名稱空間對應的內存),如果有則直接引用

如果沒有,解釋器則會查找同名的內建模塊,如果還沒有找到就從sys.path給出的目錄列表中依次尋找my_module.py文件。

所以總結模塊的查找順序是:內存中已經加載的模塊->內置模塊->sys.path路徑中包含的模塊

需要特別注意的是:我們自定義的模塊名不應該與系統內置模塊重名。

模塊和腳本

運行一個py文件有兩種方式,但是這兩種執行方式之間有一個明顯的差別,就是__name__。

1、已腳本的方式執行:cmd中“python xxx.py” 或者pycharm等IDE中執行

__name__ = '__main__'

2、導入模塊時執行:import模塊,會執行該模塊。

__name__ = 模塊名

然而,當你有一個py文件既可以作為腳本執行,又可以作為模塊提供給其他模塊引用時,這時作為模塊需要導入時而不顯示多余的打印邏輯/函數調用,所以這些邏輯可以放在“if __name__ = '__main__': xxx” 代碼塊中。

這樣py文件作為腳本執行的時候就能夠打印出來,以模塊被導入時,便不會打印出來。

from ... import ...

from...import是另一種導入模塊的形式,如果你不想每次調用模塊的對象都加上模塊名,就可以使用這種方式。

在from ... import ... 的過程中發生了什么事兒?

from my_module importname, funcprint(name) #此時引用模塊中的對象時,就不要再加上模塊名了。

func()

1、尋找模塊

2、如果找到模塊,在內存中開辟一塊內存空間,從上至下執行模塊

3、把模塊中的對應關系全部都保存到新開辟的內存空間中

4、建立一個變量xxx引用改模塊空間中對應的xxx, 如果沒有import進來的時候,就使用不了。

from ... import ... 方式取別名

與import方式如出一轍,通過"from 模塊名 import? 對象名? as? 別名"。

from my_module import name as n, func as f

from ... import *

import * 相當于把這個模塊中的所有名字都引入到當前文件中,但是如果你自己的py文件如果有重名的變量,那么就會產生不好的影響,因此使用from...import *時需要謹慎,不建議使用。

* 與 __all__

__all__是與*配合使用的,在被導入模塊中增加一行__all__=['xxx','yyy'],就規定了使用import *是只能導入在__all__中規定的屬性。

#在my_module模塊中定義__all__

__all__ = ['name']

name= 'My module...'

deffunc():print("my_module:", name)#在其他文件中通過import *導入所有屬性

from my_module import *

print(name)>>>My module...

func()>>>NameError: name'func' is not defined

拓展知識點:

(1)pyc文件與pyi文件 *

pyi文件:跟.py一樣,僅僅作為一個python文件的后綴名。

pyc文件: python解釋器為了提高加載模塊的速度,會在__pycache__目錄中生成模塊編譯好的字節碼文件,并且對比修改時間,只有模塊改變了,才會再次編譯。pyc文件僅僅用于節省了啟動時間,但是并不能提高程序的執行效率。

(2)模塊的導入和修改?*

1.導入模塊后,模塊就已經被加載到內存中,此后計算對模塊進行改動,讀取的內容還是內存中原來的結果。

2.如果想讓改動生效,可以通過“from importlib import reload”, 需要'reload 模塊名'重新加載模塊,改動才生效。

(3)模塊的循環使用 ****

謹記模塊的導入必須是單鏈的,不能有循環引用,如果存在循環,那么就是程序設計存在問題。

(4)dir(模塊名) ***

可以獲得該模塊中所有的名字,而且是字符串類型的,就可以通過反射去執行它。

包是一種通過‘.模塊名’來組織python模塊名稱空間的方式。

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

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

(3)import導入文件時,產生名稱空間中的名字來源與文件,import包,產生的名稱空間的名字同樣來源與文件,即包下的__init__.py,導入包本質就是在導入文件

注意:

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

2、創建包的目的不是為了運行,而是被導入使用,記住,包只有模塊的一種形式而已,包即模塊

包A和包B下有同名模塊也不會沖突,如A.a與B.a來自兩個命令空間

示例環境如下:

import os

os.makedirs('glance/api')

os.makedirs('glance/cmd')

os.makedirs('glance/db')

l = []

l.append(open('glance/__init__.py','w'))

l.append(open('glance/api/__init__.py','w'))

l.append(open('glance/api/policy.py','w'))

l.append(open('glance/api/versions.py','w'))

l.append(open('glance/cmd/__init__.py','w'))

l.append(open('glance/cmd/manage.py','w'))

l.append(open('glance/db/models.py','w'))

map(lambda f:f.close() ,l)

創建目錄代碼

glance/ #Top-level package

├── __init__.py #Initialize the glance package

├── api #Subpackage for api

│ ├── __init__.py

│ ├── policy.py

│ └── versions.py

├── cmd #Subpackage for cmd

│ ├── __init__.py

│ └── manage.py

└── db #Subpackage for db

│ ├── __init__.py

│ └── models.py

目錄結構

#文件內容

#policy.py

def get():

print('from policy.py')

#versions.py

def create_resource(conf):

print('from version.py: ',conf)

#manage.py

def main():

print('from manage.py')

#models.py

def register_models(engine):

print('from models.py: ',engine)

文件內容

從包中導入模塊

(1)從包中導入模塊有兩種方式,但是無論哪種,無論在什么位置,都必須遵循一個原則:(凡是在導入時帶點的,點的左邊都必須是一個包),否則非法。

(2)對于導入后,在使用就沒有這種限制,點的左邊可以是包,模塊,函數,類(它們都可以用點的方式調用自己的屬性)

(3)對比import item 和from item import name的應用場景:如果我們想直接使用name那么必須使用后者。

方式一:import

例如: 包名1.包名2.包名3.模塊名

#在與包glance同級別的文件中測試

importglance.db.models

glance.db.models.register_models('mysql')"""執行結果:from models.py mysql"""

方式二:from ... import ...

例如:from 包名1.包名2 import 模塊名

from 包名1.包名2.模塊名 import 變量名/函數名/變量名

注意:需要注意的是from后import導入的模塊,必須是明確的一個不能帶點,否則會有語法錯誤,如:from a import b.c是錯誤語法

#在與包glance同級別的文件中測試

from glance.db importmodels

models.register_models('mysql')"""執行結果:from models.py mysql"""

from glance.cmd importmanage

manage.main()"""執行結果:from manage.py"""

直接導入包

如果是直接導入一個包,那么相當于執行了這個包中的__init__文件

并不會幫你把這個包下面的其他包以及py文件自動的導入到內存

如果你希望直接導入包之后,所有的這個包下面的其他包以及py文件都能直接通過包來調用,那么需要你自己處理__init__文件。

__init__.py文件

不管是哪種方式,只要是第一次導入包或者是包的任何其他部分,都會依次執行包下的__init__.py文件;這個文件可以為空,但是也可以存放一些初始化包的代碼。

絕對導入和相對導入

我們的最頂級包glance是寫給別人用的,然后在glance包內部也會有彼此之間互相導入的需求,這時候就有絕對導入和相對導入兩種方式:

絕對導入:以glance作為起始

相對導入:用. 或者.. 的方式作為起始(只能在一個包中使用,不能用于不同目錄內)

絕對導入和絕對導入示例:

絕對導入:

既然導入包就是執行包下的__init__.py文件,那么嘗試在啊glance的__init__.py文件中"import api",執行一下,貌似沒有報錯,在嘗試下在包外導入,情況如何?

在包外創建一個test.py文件,在里面操作如下:importglance

glance.api

ModuleNotFoundError: No module named'api'原因:為什么還會報錯?因為一個模塊能不能被導入就看在sys.path中有沒有路徑,在哪里執行文件,sys.path永遠記錄該文件的目錄。

(1)在glance的__init__.py文件中,sys.path的路徑是:'E:\\Python練習\\包\\glance'所以能夠找到同級的api

(2)但是在test文件中導入,此時sys.path的路徑是:'E:\\李彥杰\\Python練習\\包'所以找不到不同層級的api,所以就會報No module name'api'解決辦法一:

使用絕對路徑(絕對路徑為當前執行文件的目錄)

(1)在glance包中的__init__.py中通過絕對路徑導入:"from glance import api"(2)這樣在test文件中執行,就能找到同層級的glance,再去里面找api

(3)同理,如果想使用api包中的模塊,也要在api包中的__init__.py文件中導入"from glance.api import policy, veersions",

(4)現在在test文件中調用glance下的api下的policy模塊就不會報錯:importglance

glance.api.policy.get()

glance.api.versions.create_resource('測試')

執行結果:frompolicy.pyfromversions.py 測試

絕對導入的缺點:

如果以后包的路徑發生了轉移,包內的所有__init__.py文件中的絕對路徑都需要改變

解決辦法二:

使用相對導入

. 表示當前目錄

.. 表示上一級目錄

(1)在glance包中的__init__.py中通過相對路徑的形式導入:

“from . importapi”

(2)同理在api包中的__init__.py中通過相對路徑的形式導入:

“from . importpolicy,version”

(3)同樣在test文件中調用glance下的api下的policy模塊就不會報錯:importglance

glance.api.policy.get()

glance.api.versions.create_resource('測試')

執行結果:frompolicy.pyfromversions.py 測試

相對導入的優點:

包發生路徑轉移,其中的相對路徑都沒有改變,所以不用逐個逐個修改。

相對導入的缺點:

但凡帶著相對導入的文件,只能當做模塊導入,不能作為一個腳本單獨執行!!!

擴展知識:

同級目錄下的包導入

需求:現在需要在bin下面的start文件中導入core目錄下的main模塊;怎么破?

project

├── bin#Subpackage for bin

├── __init__.py

└── start.py

├── core#Subpackage for core

├── __init__.py

└── main.py

#main.py文件中的內容:

deffunc():print("In main")

(1)、在start中直接導入,因為路徑不對,所以直接報錯:

import main #執行,報錯ModuleNotFoundError: No module named 'main'

(2)、由上面報錯我們知道肯定路徑不對,那么我們想到直接將core路徑加進去不就好了嗎?是的,這樣是可行的

importsys

path= 'E:\練習\包\core' #復制得到core的絕對路徑

sys.path.append(path) #將core路徑添加

import main #再次導入便不會報錯

main.func() #執行結果:In main

(3)、上面的方法看似可行,但是還是有一個問題,如果我將project打包發給別人,或者我換個環境運行呢? 那么又得更改對應的path。不怎么合理,那么我們看下面的方法:

importsysprint(__file__)

ret= __file__.split('/')

base_path= '/'.join(ret[:-2])

sys.path.append(base_path)from core importmain

main.func()#In main

1、__file__ 可以得到當前文件的絕對路徑,E:/練習/project/bin/start.py

2、__file__.split('/') 將當前文件的絕對路徑進行處理,按照'/'分隔得到:['E:', '練習', 'project', 'bin', 'start.py']

3、'/'.join(ret[:-2]) 因為我們只需要拿到project項目的動態路徑,所以進行切割,在jojn得到: E:/練習/project

4、sys.path.append(base_path) 再將得到的路徑添加到sys.path中

5、from core import main 因為我們拿到的是project目錄,所以導入是從當前路徑的core包導入main模塊

6、main.func() 最后再是模塊名.方法。

總結

以上是生活随笔為你收集整理的python包实际怎么使用_Python--模块与包的全部內容,希望文章能夠幫你解決所遇到的問題。

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