程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

【Python】模塊和包

編輯:Python

文章目錄

  • 主要內容:
    • Python 模塊初識
      • 對比C語言的 include
      • 模塊也是對象
      • 模塊的搜索路徑
      • 理解 "命名空間"
      • import語句
      • import as語句
      • from-import 語句
      • 導入模塊意味著 "被執行"
      • 理解 "導入" 和 "加載"
      • 模塊的內置變量
    • 包(Package)

主要內容:

理解模塊和包的基本概念
理解模塊的導入過程
熟悉sys模塊和os模塊中的一些重要操作


Python 模塊初識

當代碼量比較大的時候, 我們最好把代碼拆分成一些有組織的代碼片段.
每個代碼片段裡面包含一組邏輯上有關聯的函數或者類.
每一個片段裡放在一個獨立的文件中. 這樣的片段就稱為模塊(module)
使用 import 可以在一個Python文件中引入其他的模塊.

對比C語言的 include

回憶我們C語言中, 如果一個文件想使用其他文件的功能, 通過 #include 的方式來引入一個頭文件.
C語言的 #include本質上是文本替換. 因此可能會導致一系列的問題**(重復包含, 包含順序相關).**

所以通常加上:

#pragma once //防止頭文件重復包含

模塊也是對象

Python的模塊則避免了C語言中的這些問題. import 實際上是創建了一個模塊對象. 通過這個對象來訪問
模塊中的具體方法.

import os
print(type(os)) #<class 'module'> 模塊
print(id(os)) #2191830213400 有id,所以也是一個對象

模塊的搜索路徑

我們嘗試 import 一個模塊名時, Python解釋器必須要知道模塊文件的路徑

例如, 我們此處有一個add.py, 那麼對應的模塊名就是add (去掉後綴)


sys 是python標准庫自帶的模塊,一些和python解釋器相關的模塊

Python從sys.path中查找模塊.

我們可以看到, sys.path其實是一個列表. 裡面裡面的內容是Python的一些默認搜索路徑. 如果我們想再加
入一些新的路徑, 直接修改sys.path即可. ->sys.path.append('....')

import sysq
print(sys.path)
#執行結果:
['E:\\Python文件存儲', 'E:\\pythonProject1', 'C:\\Users\\Mango\\AppData\\Local\\Programs\\Python\\Python37\\python37.zip', 'C:\\Users\\Mango\\AppData\\Local\\Programs\\Python\\Python37\\DLLs', 'C:\\Users\\Mango\\AppData\\Local\\Programs\\Python\\Python37\\lib', 'C:\\Users\\Mango\\AppData\\Local\\Programs\\Python\\Python37', 'C:\\Users\\Mango\\AppData\\Local\\Programs\\Python\\Python37\\lib\\site-packages']
import sys
for line in sys.path:
print(line)
#執行結果:
E:\Python文件存儲
E:\pythonProject1
C:\Users\Mango\AppData\Local\Programs\Python\Python37\python37.zip
C:\Users\Mango\AppData\Local\Programs\Python\Python37\DLLs
C:\Users\Mango\AppData\Local\Programs\Python\Python37\lib
C:\Users\Mango\AppData\Local\Programs\Python\Python37
C:\Users\Mango\AppData\Local\Programs\Python\Python37\lib\site-packages

import語句不一定非要寫在源代碼文件的最開始(推薦寫在最上面)

如果在多個目錄中, 都存在相同名字的模塊, 這個時候Python解釋器會從前往後順序查找, 把找到的第一個
匹配的結果進行加載.


理解 “命名空間”

名字沖突問題: 如果一個項目中的代碼量很大, 那麼很可能函數/類的名字會沖突.

C語言采用的方案是,給函數名加一個又丑又長的前綴

void Huichuan_AdServer_Strategy_IndexAccessor_Load()

C++中使用命名空間來解決這個問題

namespace Huichuan {

namespace AdServer {

namespace Strategy {

namespace IndexAccessor {

void Load()
}
}
}
}

Python的模塊也相當於是命名空間. 例如 os.path.exists , 通過這樣的層級結構, 將函數的名字組織起來, 就可以有效的避免命名沖突.


import語句

import語句導入模塊, 可以一次import一個, 或者一次import多個->用,分割

#方式1:
import os
import sys
#方式2:
import os,sys #用逗號分割

推薦使用第一種方式, 這樣代碼看起來更好看一些


import語句的順序: 我們推薦按 Python標准庫, Python第三方庫, 應用程序自定制模塊 的順序來import,
來提高我們代碼的可讀性.

模塊也是一個對象, 也有作用域這樣的概念. 在函數內部import, 那麼這個模塊的作用域就是在這個函
數內.

例子:

def func():
import sys
print('In func',sys.argv) #In func ['E:/Python文件存儲/Class01.py']
func()
print('Out func',sys.argv) #報錯 NameError: name 'sys' is not defined

既然模塊也是一個對象, 那麼也可以給這個對象賦值(相當於定義別名).

import os.path
p = os.path #起別名
print(p.exists('add.py')) #add.py這個文件是否存在 True

這樣可以一定程度上簡化我們的代碼(敲一個字符p肯定比敲一串字符os.path要方便).


import as語句

前面我們使用賦值的方式, 給模塊起了一個很短的別名. 實際上使用import-as可以更方便的完成這個動作

import os.path as p
print(p.exists('add.py')) #add.py這個文件是否存在 True

from-import 語句

import語句是直接導入一個模塊. 而有時候我們只需要用到模塊中的某一個或幾個函數, 就可以使用from-
import

from-import相當於把模塊中的名字引入了當前文件的命名空間中.可以直接使用導入的函數

from os.path import exists
print(exists('add.py')) #True

可以使用 from module import * 的方式將module模塊中的所有名字都導入進來. 不推薦這麼用.

*:通配符


導入模塊意味著 “被執行”

模塊導入意味著這個模塊 “被執行” , 也就是說所有頂層的代碼(無縮進部分的代碼)都會被執行到. 這通常包括函數的定義和全局變量的定義.

例子:

add.py 的內容:

''' 定義兩數相加的函數 '''
def _Add(x,y):
return x+y
print("In Add函數內部")

test.py的內容

import add
#執行結果:
In Add函數內部

這往往不是我們期望的結果(比如導入模塊是打印了一些奇怪的日志), 我們只是想使用模塊中的一些函數和變量. 因此往往我們在實現一個模塊時, 只將函數定義/類定義放到頂層代碼中.


理解 “導入” 和 “加載”

我們寫 import module 時, 其實有兩個大的階段, 先將這個模塊的文件加載到內存中, 並創建一個對象來表示; 然後通過一個變量名來將這個模塊引入到當前的命名空間中.

如果同一個模塊(例如sys這樣的常用模塊)被import了多次, 其實加載動作只進行了一次(也就是說內存中只有一份sys的代碼), 執行動作也只進行了一次

import add
import add
#執行結果:
In Add函數內部

模塊的內置變量

我們可以通過globals()函數看到全局命名空間下有幾個內置變量

print(globals())
#執行結果:
{
'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000026C824D6400>, '__spec__': None, '__annotations__': {
}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/Python文件存儲/Class01.py', '__cached__': None}

其中:

_builtins_ : 內建函數模塊. 包含了open, help, doc等內建函數的定義
__name__ : **模塊名字. 如果是從這個模塊開始執行, 那麼 __name__ 值為 __main__,否則就是當前文件不包含後綴的名稱

入口文件是誰,__name__就是__name__

__file__ : 模塊的文件名
__doc__ : 模塊的文檔字符串
__package__ :模塊從屬的包名


回憶我們剛剛講過的, import的時候, 會執行這個模塊. 我們期望, 這個模塊被別人導入時, 只進行函數定義; 如果直接從這個模塊開始運行, 則在函數定義完成後再進行一些測試

例子:

''' 定義兩數相加的函數 '''
def Add(x,y):
return x+y
#測試:
if __name__ == '__main__':
print(Add(1,2))
print(Add(2,3))

判定 __name__ 是否值為 _main_ , 如果是的話, 說明是直接執行add.py, 這時候就執行測試代碼. 否則
認為add是被其他Python文件import的, 不執行測試代碼.

包(Package)

當我們代碼量進一步變大時, 光拆分成多個文件已經不足以滿足需求, 還需要能按照一定的目錄結構層次化的組織這些模塊. 同時包也可以解決模塊之間的名字沖突問題.

目錄也是包的一種 ,包也是模塊

如:以下面的方式組織代碼結構:

test.py
calc/
add.py
__init__.py

在calc目錄中增加一個 _init_.py 文件, calc這個目錄就成了包(Package). 可以在test.py文件中import calc中的模塊了

**_init.py_**是包的初始化文件, 會首先執行它


__init__.py 是在包加載的時候會進行執行, 負責一些包的初始化操作. 一般是空文件即可.


包中是可以嵌套其他的包的


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved