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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > python >内容正文

python

每个python文件就是一个模块、模块的名字就是_Python-模块和包

發(fā)布時(shí)間:2024/8/1 python 63 豆豆
生活随笔 收集整理的這篇文章主要介紹了 每个python文件就是一个模块、模块的名字就是_Python-模块和包 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

今天我們來聊聊模塊和包

一.模塊

首先,我們先看一個(gè)老生常談的問題,什么是模塊,模塊就是一個(gè)包含了python定義和聲明的文件,文件名就是模塊的名字加上.py后綴,歡聚話說我們目前寫的所有的py文件都可以看成是一個(gè)模塊但是我們import加載的模塊一共分成四個(gè)通用類別:

1. 使用pyhton編寫的py文件

2. 已被變異為共享庫(kù)或者DLL或C或者C++的擴(kuò)展

3. 包好一組模塊的包.

4. 使用c編寫并連接到python解釋器的內(nèi)置模塊

為什么要使用模塊? 為了我們寫的代碼可以重用,不至于把所有的代碼都寫在一個(gè)文件內(nèi). 當(dāng)項(xiàng)目規(guī)模比較小的時(shí)候,完全可以使用一個(gè)py搞定整個(gè)項(xiàng)目的開發(fā),但是如果是一個(gè)非常龐大的項(xiàng)目. 此時(shí)就必須要把相關(guān)的功能進(jìn)行分離,以便我們的日常維護(hù),以及新項(xiàng)目的開發(fā).

如何使用模塊? 我們已用過很多模塊了,導(dǎo)入模塊有兩種方式

1. import 模塊

2. from xxx import xxxx

二.import

首先我們先看import, 在使用import的時(shí)候, 我們先創(chuàng)建一個(gè)yitian.py. 在該文件中創(chuàng)建一些武林前輩和一些打斗場(chǎng)景, 代碼如下:

print("片頭曲. 啊! 啊~ 啊! 啊. 啊啊啊啊啊啊啊...")

main_person_man = "張無忌"

main_person_woman = "趙敏"

low_person_man_one = "成昆"

low_person_man_two = "周芷若"

def fight_on_light_top():

print("光明頂大戰(zhàn)", main_person_man, "破壞了", low_person_man_one, "的大陰謀")

def fight_in_shaolin():

print("少林寺大戰(zhàn)", main_person_man, "破壞了", low_person_man_two, "的大陰

謀")

接下來,金庸上場(chǎng)

import yitian

print(yitian.main_person_man) # 使用模塊中定義好的名字

print(yitian.low_person_man_one)

yitian.fight_in_shaolin() # 調(diào)用模塊中的函數(shù)

yitian.fight_on_light_top()

此時(shí)我們?cè)诮鹩鼓K中引入了yitian模塊.

在Python中模塊是不能夠重復(fù)導(dǎo)入的,當(dāng)重復(fù)導(dǎo)入模塊時(shí),系統(tǒng)會(huì)根據(jù)sys.modules來判斷該模塊是否已經(jīng)導(dǎo)入了,如果已經(jīng)導(dǎo)入,則不會(huì)重復(fù)導(dǎo)入

import sys

print(sys.modules.keys()) # 查看導(dǎo)入的模塊.

import yitian # 導(dǎo)入模塊. 此時(shí)會(huì)默認(rèn)執(zhí)行該模塊中的代碼

import yitian # 該模塊已經(jīng)導(dǎo)入過了,不會(huì)重復(fù)執(zhí)行代碼

import yitian

import yitian

import yitian

import yitian

導(dǎo)入模塊的時(shí)候都做了些什么? 首先,在導(dǎo)入模塊的一瞬間,python解釋器會(huì)先通過sys.modules來判斷該模塊是否已經(jīng)導(dǎo)入了該模塊,如果已經(jīng)導(dǎo)入了則不再導(dǎo)入,如果該模塊還未導(dǎo)入過,則系統(tǒng)會(huì)做三件事.

1. 為導(dǎo)入的模塊創(chuàng)立新的名稱空間

2. 在新創(chuàng)建的名稱空間中運(yùn)行該模塊中的代碼

3. 創(chuàng)建模塊的名字,并使用該名稱作為該模塊在當(dāng)前模塊中引用的名字.

我們可以使用globals來查看模塊的名稱空間

print(globals())

打印結(jié)果:

{'__name__': '__main__', '__doc__': None, '__package__': None,

'__loader__': <_frozen_importlib_external.sourcefileloader object at>

0x10bbcf438>, '__spec__': None, '__annotations__': {}, '__builtins__':

, '__file__':

'/Users/sylar/PycharmProjects/oldboy/模塊/模塊/?庸.py', '__cached__': None,

'yitian':

塊/yitian.py'>, 'sys': }

注意,由于模塊在導(dǎo)入的時(shí)候會(huì)創(chuàng)建其自己的名稱空間,所以我們?cè)谑褂媚K中的變量的時(shí)候一般是不會(huì)產(chǎn)生沖突的.

import yitian

main_person_man = "胡一菲"

def fight_in_shaolin():

print(main_person_man, "大戰(zhàn)曾小賢")

print(yitian.main_person_man) # 張無忌

print(main_person_man) # 胡一菲

yitian.fight_in_shaolin() # 倚天屠龍記中的

fight_in_shaolin() # 自己的

注意,在模塊中使用global,我們之前說global表示把全局的內(nèi)容引入到局部,但是這個(gè)全局指的是py文件,換句話說,global指向的是模塊內(nèi)部,并不會(huì)改變外部模塊的內(nèi)容

模塊 yitian 中:

print("片頭曲. 啊! 啊~ 啊! 啊. 啊啊啊啊啊啊啊...")

main_person_man = "張無忌"

main_person_woman = "趙敏"

low_person_man_one = "成昆"

low_person_man_two = "周芷若"

def fight_on_light_top():

print("光明頂大戰(zhàn)", main_person_man, "破壞了", low_person_man_one, "的大陰謀")

def fight_in_shaolin():

global low_person_man_two # 注意看, 此時(shí)的global是當(dāng)前模塊. 并不會(huì)影響

其他模塊

low_person_man_two = "戰(zhàn)五渣"

print("少林寺大戰(zhàn)", main_person_man, "破壞了", low_person_man_two, "的大陰謀")

調(diào)用方:

import yitian

low_person_man_two = "劉海柱"

yitian.fight_in_shaolin()

print(yitian.low_person_man_two) # 戰(zhàn)五渣

print(low_person_man_two) # 劉海柱. 并沒有改變當(dāng)前模塊中的內(nèi)容. 所以模塊內(nèi)部的

global只是用于模塊內(nèi)部

特別特別要注意,如果我們?cè)诓煌哪K中引入了同一個(gè)模塊,并且在某一個(gè)模塊中改變了被引入模塊中的全局變量,則其他模塊看到的值也跟著變,原因是python的模塊只會(huì)引入一次,大家共享同一個(gè)名稱空間

金庸:

import yitian

yitian.main_person_man = "滅絕師太"

金庸二號(hào):

import yitian

import 金庸

print(yitian.main_person_man) # 滅絕師太.

上述問題出現(xiàn)的原因:

1. 大家共享同一個(gè)模塊的名稱空間.

2. 在金庸里改變了主?的名字

如何解決呢?

首先, 我們不能去改python,因?yàn)閜ython的規(guī)則不是我們定的,只能想辦法不要改變主?的名字,但是在金庸里我就有這樣的需求,那此時(shí)就出現(xiàn)了,在金庸被執(zhí)行的時(shí)候要執(zhí)行的代碼,在金庸被別人導(dǎo)入的時(shí)候我們不想執(zhí)行這些代碼,此時(shí)我們就要利用一下__name__這個(gè)內(nèi)置變量了. 在Python中,每個(gè)模塊都有自己的__name__ ,但是這個(gè)__name__的值是不定的,當(dāng)我們把一個(gè)模塊作為程序運(yùn)行的入口時(shí),此時(shí)該模塊的__name__是"__main__" , 而如果我們把模塊導(dǎo)入時(shí),此時(shí)模塊內(nèi)部的__name__就是該模塊自身的名字

金庸:

print(__name__)

# 此時(shí)如果運(yùn)行該文件,則__name__是__main__

金庸二號(hào):

import 金庸

#此時(shí)打印的結(jié)果是"金庸"

我們可以利用這個(gè)特性來控制模塊內(nèi)哪些代碼是在被加載的時(shí)候就運(yùn)行的,哪些是在模塊被別人導(dǎo)入的時(shí)候就要執(zhí)行的,也可以屏蔽掉一些不希望別人導(dǎo)入就運(yùn)行的代碼,尤其是測(cè)試代碼.

if __name__ == '__main__':

yitian.main_person_man = "滅絕師太" # 此時(shí), 只有從該模塊作為入口運(yùn)行的時(shí)候才

會(huì)把main_person_man設(shè)置成滅絕師太

print("哇哈哈哈哈哈") # 只有運(yùn)行該模塊才會(huì)打印,import的時(shí)候是不會(huì)執(zhí)行這里的代

碼的

我們還可以對(duì)導(dǎo)入的模塊進(jìn)行重新命名:

import yitian as yt # 導(dǎo)入yitian. 但是名字被重新命名成了yt. 就好比變量賦值一樣.

a = 1 b = a

yt.fight_in_shaolin() # 此時(shí)可以正常運(yùn)行

# yitian.fight_in_shaolin() # 此時(shí)程序報(bào)錯(cuò). 因?yàn)橐氲膟itian被重命名成了yt

print(globals())

{'__name__': '__main__', '__doc__': None, '__package__': None,

'__loader__': <_frozen_importlib_external.sourcefileloader object at>

0x103209438>, '__spec__': None, '__annotations__': {}, '__builtins__':

, '__file__':

'/Users/sylar/PycharmProjects/oldboy/模塊/模塊/金庸.py', '__cached__': None,

'yt':

塊/yitian.py'>}

一次可以引入多個(gè)模塊

import time, random, json, yitian

正確的導(dǎo)入模塊的順序:

1. 所有的模塊導(dǎo)入都要寫在最上面,這是最基本的

2. 先引入內(nèi)置模塊

3. 再引入擴(kuò)展模塊

4. 最后引入你自己定義的模塊

三. from xxx import xxx

第一大塊關(guān)于import就說這么多,接下來我們來看from xxx import xxx這種導(dǎo)入模塊的效果,在使用from的時(shí)候, python也會(huì)給我們的模塊創(chuàng)建名稱空間,這一點(diǎn)和import是一樣的,但是from xxx import xxx的時(shí)候,我們是把這個(gè)空間中的一些變量引入過來了,說白了就是部分導(dǎo)入,當(dāng)一個(gè)模塊中的內(nèi)容過多的時(shí)候,我們可以選擇性的導(dǎo)入要使用的內(nèi)容.

from yitian import fight_in_shaolin

fight_in_shaolin()

此時(shí)是可以正常運(yùn)行的,但是我們省略了之前的模塊.函數(shù)() 直接函數(shù)()就可以執(zhí)行了, 并且from語(yǔ)句也支持一行語(yǔ)句導(dǎo)入多個(gè)內(nèi)容

from yitian import fight_in_shaolin, fight_on_light_top, main_person_man

fight_in_shaolin()

fight_on_light_top()

print(main_person_man)

同樣支持as

from yitian import fight_in_shaolin, fight_on_light_top, main_person_man as

big_lao

fight_in_shaolin()

fight_on_light_top()

print(big_lao)

最后看一下from的坑,當(dāng)我們從一個(gè)模塊中引入一個(gè)變量的時(shí)候,如果當(dāng)前文件中出現(xiàn)了重名的變量時(shí),會(huì)覆蓋掉模塊引入的那個(gè)變量.

from yitian import main_person_man

main_person_man = "超級(jí)大滅絕"

print(main_person_man)

所以,不要重名,切記,不要重名! 不僅僅是變量名不要重復(fù),我們自己創(chuàng)建的py文件的名字不要和系統(tǒng)內(nèi)置的模塊重名,否則引入的模塊都是python內(nèi)置的模塊. 切記, 切記.

我們現(xiàn)在知道可以使用import和from xxx import xxx來導(dǎo)入一個(gè)模塊中的內(nèi)容,那有一種特殊的寫法: from xxx import * 我們說此時(shí)是把模塊中的所有內(nèi)容都導(dǎo)入, 注意,如果模塊中沒有寫出__all__ 則默認(rèn)所有內(nèi)容都導(dǎo)入,如果寫了__all__ 此時(shí)導(dǎo)入的內(nèi)容就是在__all__列表中列出來的所有名字.

# haha.py

__all__ = ["money", "chi"]

money = 100

def chi():

print("我是吃")

def he():

print("我是呵呵")

# test.py

from haha import *

chi()

print(money)

# he() # 報(bào)錯(cuò)

四.包

包是一種通過 '.模塊名'來組織python模塊名稱空間的方式,那什么樣的東西是包呢? 我們創(chuàng)建的每個(gè)文件夾都可以被稱之為包,但是我們要注意, 在python2中規(guī)定,包內(nèi)必須存在__init__.py文件,創(chuàng)建包的目的不是為了運(yùn)行, 而是被導(dǎo)入使用,包只是一種形式而已,包的本質(zhì)就是一種模塊

為何要使用包? 包的本質(zhì)就是一個(gè)文件夾, 那么文件夾唯一的功能就是將文件組織起來,隨著功能越寫越多, 我們無法將所有功能都放在一個(gè)文件中, 于是我們使用模塊去組織功能隨著模塊越來越多, 我們就需要用文件夾將模塊文件組織起來, 以此來提高程序的結(jié)構(gòu)性和可維護(hù)性

首先, 我們先創(chuàng)建一些包,用來作為接下來的學(xué)習(xí),包很好創(chuàng)建,只要是一個(gè)文件夾, 有__init__.py就可以

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/__init__.py','w'))

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

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

創(chuàng)建好目錄結(jié)構(gòu)

我們接下來給每個(gè)文件中添加一些方法:

#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)

接下來我們?cè)趖est中使用包中的內(nèi)容,并且我們導(dǎo)入包的時(shí)候可以使用import或者from xxx import xxx這種形式.

首先, 我們看import

import glance.db.models

glance.db.models.register_models('mysql')

沒問題, 很簡(jiǎn)單, 我們還可以使用from xxx import xxx 來導(dǎo)入包內(nèi)的模塊

from glance.api.policy import get

get()

也很簡(jiǎn)單, 但是要注意,from xxx import xxx這種形式, import后面不可以出現(xiàn)"點(diǎn)" 也就是說from a.b import c是ok的,但是 from a import b.c 是錯(cuò)誤的

好了, 到目前為止, 簡(jiǎn)單的包已經(jīng)可以使用了,那包里的__init__.py是什么鬼? 其實(shí)不論我們使用哪種方式導(dǎo)入一個(gè)包, 只要是第一次導(dǎo)入包或者是包的任何其他部分, 都會(huì)先執(zhí)行__init__.py文件,這個(gè)文件可以是空的,但也可以存放一些初始化的代碼. (隨意在glance中的__init__.py都可以進(jìn)行測(cè)試)

那我們之前用的from xxx import *還可以用么? 可以,我們要在__init__.py文件中給出_all__來確定* 導(dǎo)入的內(nèi)容.

print("我是glance的__init__.py文件. ")

x = 10

def hehe():

print("我是呵呵")

def haha():

print("我是哈哈")

__all__ = ['x', "hehe"]

test.py

from glance import *

print(x) # OK

hehe() # OK

haha() # 報(bào)錯(cuò). __all__里沒有這個(gè)鬼東西

接下來, 我們來看一下絕對(duì)導(dǎo)入和相對(duì)導(dǎo)入, 我們的最頂級(jí)包glance是寫給別人用的,然后再glance包內(nèi)部也會(huì)有彼此之間互相導(dǎo)入的需求, 這時(shí)候就有絕對(duì)導(dǎo)入和相對(duì)導(dǎo)入兩種方式了.

1. 絕對(duì)導(dǎo)入: 以glance作為起始

2. 相對(duì)導(dǎo)入: 用. 或者..作為起始

例如, 我們?cè)趃lance/api/version.py中使用glance/cmd/manage.py

# 在glance/api/version.py

#絕對(duì)導(dǎo)入

from glance.cmd import manage

manage.main()

#相對(duì)導(dǎo)入

# 這種情形不可以在versions中啟動(dòng)程序.

# attempted relative import beyond top-level package

from ..cmd import manage

manage.main()

測(cè)試的時(shí)候要注意,python包路徑跟運(yùn)行腳本所在的目錄有關(guān)系,說白了就是你運(yùn)行的py文件所在的目錄,在python中不允許你運(yùn)行的程序?qū)О臅r(shí)候超過當(dāng)前包的范圍(相對(duì)導(dǎo)入). 如果使用絕對(duì)導(dǎo)入,沒有這個(gè)問題,換個(gè)說法,如果你在包內(nèi)使用了相對(duì)導(dǎo)入,那在使用該包內(nèi)信息的時(shí)候,只能在包外面導(dǎo)入.

接下來我們來看一個(gè)大坑,比如,我們想在policy中使用verson中的內(nèi)容.

# 在policy.py

import versions

如果我們程序的入口是policy.py 那此時(shí)程序是沒有任何問題的,但是如果我們?cè)趃lance外面import了glance中的policy就會(huì)報(bào)錯(cuò) ,原因是如果在外面訪問policy的時(shí)候,sys.path中的路徑就是外面, 所以根本就不能直接找到versions模塊,所以一定會(huì)報(bào)錯(cuò):

ModuleNotFoundError: No module named 'versions'

在導(dǎo)包出錯(cuò)的時(shí)候,一定要先看sys.path 看一下是否真的能獲取到包的信息.

最后, 我們看一下如何單獨(dú)導(dǎo)入一個(gè)包.

# 在test.py中

import glance

此時(shí)導(dǎo)入的glance什么都做不了,因?yàn)樵趃lance中的__init__.py中并沒有關(guān)于子包的加載,此時(shí)我們需要在__init__.py中分別去引入子包中的內(nèi)容.

1. 使用絕對(duì)路徑

2. 使用相對(duì)路徑

包的注意事項(xiàng):

1. 關(guān)于包相關(guān)的導(dǎo)入語(yǔ)句也分為import和from xxx import xxx兩種, 但無論使用哪種,無論在什么位置, 在導(dǎo)入時(shí)都必須遵循一個(gè)原則: 凡是在導(dǎo)入時(shí)d帶點(diǎn)的,點(diǎn)左邊都必須是一個(gè)包,否則報(bào)錯(cuò),可以帶一連串的點(diǎn), 比如a.b.c

2. import導(dǎo)入文件時(shí),產(chǎn)生名稱空間中的名字來源于文件, import 包, 產(chǎn)生的名稱空間中的名字同樣來源于文件, 即包下的__init__,py, 導(dǎo)入包本質(zhì)就是在導(dǎo)入該文件

3. 包A和包B下有同名模塊也不會(huì)沖突, 如A.a和B.a來自兩個(gè)名稱空間

總結(jié)

以上是生活随笔為你收集整理的每个python文件就是一个模块、模块的名字就是_Python-模块和包的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。