【模組二】Python進階

七星海棠^_~發表於2024-07-06

函式基礎

函式的本質就是一功能程式碼塊組織在一個函式名下,可以反覆呼叫

1.去重 函式可以減少程式碼的重複性。透過將重複的程式碼邏輯封裝成函式。可以避免再不同的地方重複編寫相同的程式碼

**2.解耦 ** 函式對程式碼的組織結構化可以將程式碼分成邏輯上獨立的模組,提高程式碼的可讀性和可維護性,從而實現解耦

函式的宣告和呼叫
# 宣告
def 函式名():
    # 函式體【功能模組】
# 呼叫
函式名()
函式的引數

函式的引數指的是函式定義中宣告的變數,用於接收函式呼叫時傳遞的資料。引數允許我們將值或引用傳遞給函式,以便在函式內部進行計算、操作、處理。

函式引數可以有多個,每個引數都有一個名稱和型別。函式定義中的引數稱為形式引數即形參,而函式呼叫時傳遞的引數成為實際引數實參

函式的引數允許函式在不同的上下文中接收不同的資料,並且增加了函式的靈活性和可複用性。

1.內建函式:print,type都需要傳引數

2.函式傳遞引數本質是變數賦值,且該變數只在函式執行時存在,執行結束後銷燬

位置引數

位置引數是按照定義時的順序進行傳遞的引數。呼叫函式時,實參的位置必須與形參的位置一一對應。

預設引數

預設引數是在函式宣告時為引數指定的預設值。如果在函式呼叫時沒有傳遞函式的引數,函式將使用預設值。

如果有預設引數,一定要放在非預設引數的後面

關鍵字引數

關鍵字引數是透過指定引數名來傳遞的引數。呼叫函式時,可以根據引數名來傳遞實參,而不必遵循形參的順序。

關鍵字引數一定要放在位置引數後面

可變引數

可變數量引數允許函式接收不定數量的引數。可以使用特殊符號來表示可變數量的引數,如*args用於接收任意數量的位置引數**kwargs用於接收任意數量的關鍵字引數

函式的作用域

作用域(Scope)是指在程式中定義變數或函式時,這些變數或函式可以被訪問的範圍。變數和函式的可見性和訪問性是不同的。

當訪問一個變數時,會按照LEGB的順序進行查詢,直到找到第一個匹配的變數,然後停止查詢。如果在所有作用域中都找不到變數的定義,就會引發NameError。

  • L (Local): 區域性作用域。包含函式內部定義的變數和引數。在函式內部最先進行變數查詢。
  • E (Encloaing): 巢狀函式的父函式的作用域。如果在當前函式內部找不到變數,就會向上一層巢狀的函式中查詢。
  • G (Global):全域性作用域。在模組層次定義的變數,對於整個模組都是可見的。
  • B (Built-in):內建作用域。包含python的內建函式和異常。

global關鍵字用於在函式內部宣告一個變數為全域性變數,表示在函式內部對該變數的修改將影響到全域性作用域中的變數。

nonlocal關鍵字用於在函式內部宣告一個變數為非本地變數,表示在函式內部對該變數的修改將影響到上一級的巢狀作用域中的變數。

函式的返回值

函式的返回值是指函式執行完畢後,透過return語句返回給呼叫者的結果。

使用return語句可以將一個值或物件作為函式的返回值返回。這個返回值可以是任何有效的python物件,例如數字、字串、列表、字典等。函式執行到return語句時,會立即結束函式的執行,並將指定的返回值傳遞給呼叫者。

如果函式內沒有return,預設返回None,代表沒有什麼結果返回

常用內建函式
模式 功能
input([promopt]) 從控制檯獲取使用者輸入
print() 將一個或多個物件列印到控制檯
type(object) 返回物件的型別
range(stop) 生成一個序列
id(object) 獲取物件的記憶體地址
len(s) 返回物件的長度
str(object='') 將值轉換為字串
repr(object) 返回物件的字串表示形式
int(x=0) 將一個字串或數字轉換為整數
float(x) 將一個字串或數字轉換為浮點數
bool(x) 將值x轉換為布林值
list([iterable]) 將一個序列轉換為列表
tuple([iterable]) 將一個序列轉換為元組
set([iterable]) 返回一個新的集合物件
bin(x) 將整數x轉換為一個二進位制字串
hex(x) 將整數x轉換為十六進位制字串
oct(x) 將整數x轉換為八進位制字串
abs(x) 返回x的絕對值
pow(x, y[, z]) 返回x的y次冪,如果z給出,則對其結果取模
max(iterable) 返回序列中最大的元素
min(iterable) 返回序列中最小的元素
round(number[, ndigits]) 將一個數四捨五入到指定的精度
sum(iterable) 返回序列元素的總和
divmod(a, b) 返回a和b的商和餘數元組
enumrate(iterable, start=0) 返回列舉物件
eval() 將字串作為表示式求值,並返回結果
ord 返回字元c的ASCII碼
chr(i) 返回證書i對應的ASCII字元
reversed(seq) 返回序列seq的反轉序列
filter(function, iterable) 過濾序列,過濾掉不符合條件的元素
map(function, iterable) 對序列中的每個元素應用function函式
sorted(iterable |key][reverse]) 返回一個列表,其中的元素按指定的鍵排序
open() 開啟一個檔案,並返回一個檔案物件

檔案操作

字元編碼

編碼是將字元轉換為特定編碼標準下的二進位制表示形式,而解碼則是將二進位制資料轉換為字元形式。

encoded = text.encoding('utf8')
decoded = encoded.decode('utf8')
檔案操作
open(file, mode='r', encoding=None)
模式 意義 注意事項
r 只讀模式開啟檔案,讀檔案內容的指標會放在檔案開頭 操作的檔案必須存在
rb 以二進位制格式,只讀模式開啟檔案,讀檔案內容的指標會放在檔案開頭。一般用於非文字檔案,如圖片、音訊等 操作的檔案必須存在
r+ 開啟檔案後,既可以從頭讀取檔案內容,也可以從開頭向檔案中寫入新的內容,寫入的新內容會覆蓋檔案中等長度的原有內容 操作的檔案必須存在
rb+ 以二進位制格式,採用讀寫模式開啟檔案,讀檔案內容的指標會放在檔案開頭。一般用於非文字檔案,如圖片、音訊等 操作的檔案必須存在
w 以只寫模式開啟檔案,若檔案存在,開啟時會清空檔案中原有的內容 若檔案存在,會清空其原有內容,覆蓋內容;反之,則建立新檔案
wb 以二進位制格式,以只寫模式開啟檔案,一般用於非文字檔案。 若檔案存在,會清空其原有內容,覆蓋內容;反之,則建立新檔案
w+ 開啟檔案後,會對原有的內容進行清空,並對該檔案有讀寫許可權 若檔案存在,會清空其原有內容,覆蓋內容;反之,則建立新檔案
wb+ 以二進位制格式,讀寫模式開啟,一般用於非文字檔案。 若檔案存在,會清空其原有內容,覆蓋內容;反之,則建立新檔案
a 追加模式,只寫許可權。如果檔案已存在,檔案指標將在文末;反之,會建立新檔案
ab 以二進位制格式,追加模式,只寫許可權。如果檔案已存在,檔案指標將在文末;反之,會建立新檔案
a+ 以讀寫模式開啟檔案。如果檔案已存在,檔案指標將在文末;反之,會建立新檔案
ab+ 以二進位制格式,追加模式,只寫許可權。如果檔案已存在,檔案指標將在文末;反之,會建立新檔案
讀檔案
# 讀取整個檔案內容
f.read()
# 讀取一行內容
f.readline()
# 讀取所有行內容並返回列表
f.readlines()
寫檔案
# 向檔案寫入內容
f.write()
# 將字串列表寫入檔案中
f.writelines()
with open
# 自動分配並且釋放資源
with open("file.txt", "r") as file:
    content = file.read()
    # 在這裡進行檔案操作,檔案會在程式碼塊結束後自動關閉

常用模組

random模組
  • random() 生成一個0到1之間的隨機浮點數
  • random(a, b) 生成一個指定範圍內的隨機整數,包括ab
  • choice(seq) 從給定的序列中隨機選擇一個元素
  • sample(seq, k) 從給定的序列中隨機選擇k個元素,返回一個新的列表
  • shuffle(seq) 隨機打亂給定序列的順序
time模組
  1. 獲取當前時間

    • time() 返回從1970年1月1日午夜開始經過的秒數(Unix時間戳)。
  2. 時間延遲和暫停

    • sleep(secs) 暫停指定的秒數。
  3. 時間戳和時間元組互換

    • localtime([secs]) 將秒數轉換為當前時區的struct_time物件。

    • mktime(t) 將struct_time物件轉換為秒數。

    • gmtime([secs]) 將秒數轉換為UTC時間的struct_time物件。

  4. 時間格式化

    • strftime(format, t) 將時間元組物件t按照指定格式format進行格式化輸出
datetime模組
datetime類
import datetime

# (1) 獲取datetime物件

datetime.datetime.now():返回當前的本地日期和時間。
datetime.datetime.today():返回當前日期的datetime物件(時間部分為0時0分0秒)

#  建立特定日期和時間的物件:
datetime.datetime(year, month, day, hour=0, minute=0, second=0, microsecond=0):建立一個代表特定日期和時間的 datetime 物件。

# (2) datetime物件屬性:

datetime_obj.year:年份。
datetime_obj.month:月份。
datetime_obj.day:日期。
datetime_obj.hour:小時。
datetime_obj.minute:分鐘。
datetime_obj.second:秒數。

# (3) datetime物件和格式化字串轉換

# datetime物件轉為格式化字串

current_datetime = datetime.datetime.now()
format = "%Y-%m-%d %H:%M:%S"
formatted_datetime = current_datetime.strftime(format)
print(formatted_datetime)  # 輸出:2022-01-01 12:30:45
print(type(formatted_datetime))  # 輸出:<class 'str'>

# 時間字串轉為datetime物件

date_string = "2022-01-01 12:30:45"
format = "%Y-%m-%d %H:%M:%S"
parsed_datetime = datetime.datetime.strptime(date_string, format)
print(parsed_datetime)  # 輸出:2022-01-01 12:30:45
date類
import datetime

# (1) 獲取當前日期物件
today = datetime.date.today()
print(today)

# (2) 日期物件屬性:

date_obj.year:年份。
date_obj.month:月份。
date_obj.day:日期。

# (3) date物件轉為格式化字串

today = datetime.date.today()
formatted_date = today.strftime("%Y-%m-%d")
print(formatted_date)  # 輸出:2024-02-13
timedelta類
timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0):建立一個 timedelta 物件。
timedelta.total_seconds():返回時間間隔的總秒數。

import datetime

# 案例1
from datetime import date

today = date.today()
birthday = date(1998, 5, 15)
age = today - birthday
print("Age:", age.days)

# 案例2
now = datetime.datetime.now()
ret = now + datetime.timedelta(days=3)
print(ret)
sys模組
  • sys.argv:命令列引數的列表,包括指令碼名稱和傳遞給指令碼的引數。
  • sys.exit([arg]):退出當前程式的執行,並返回可選的錯誤程式碼 arg。
  • sys.path:一個列表,包含用於查詢模組的搜尋路徑。
  • sys.version:當前 Python 直譯器的版本資訊。
os模組
  1. 檔案和目錄操作:
    • os.getcwd(): 獲取當前工作目錄的路徑。
    • os.chdir(path): 修改當前工作目錄為指定路徑。
    • os.listdir(path): 返回指定目錄中的檔案和目錄列表。
    • os.mkdir(path): 建立一個新的目錄。
    • os.makedirs(path): 遞迴建立目錄,包括中間目錄。
    • os.remove(path): 刪除指定的檔案。
    • os.rmdir(path): 刪除指定的空目錄。
    • os.removedirs(path): 遞迴刪除目錄,包括所有子目錄。
    • os.rename(src, dst): 將檔案或目錄從src重新命名為dst。
  2. 作業系統命令:
    • os.system(command): 執行作業系統命令。
    • os.popen(command): 執行作業系統命令,並返回一個檔案物件。
  3. 路徑操作:
    • os.path.join(path1, path2, ...): 將多個路徑組合成一個路徑。
    • os.path.split(path): 將路徑分割成目錄和檔名。
    • os.path.dirname(path): 返回路徑的目錄部分。
    • os.path.basename(path): 返回路徑的檔名部分。
    • os.path.exists(path): 檢查路徑是否存在。
    • os.path.abspath(): 返回絕對路徑
json模組

序列化是將資料結構或物件轉換為位元組流(二進位制資料)以便儲存或傳輸

反序列化是將位元組流還原為原始資料結構或物件的過程

JSON(JavaScript Object Notation, JS 物件標記)是一種輕量級的資料交換格式。

Python JSON
dict object
list, tuple array
str string
int, float number
True true
False false
None null
# 序列化	將本語言支援的高階資料物件轉為json格式字串的過程

num = 3.14
name = 'yuan'
l = [1, 2, 3]
t = (4, 5, 6)
d = {'name': "yuan", 'age': 18, "is_married": False, "gf": None}

print(repr(json.dumps(num)))  # '3.14'
print(repr(json.dumps(name)))  # '"yuan"'
print(repr(json.dumps(l)))  # '[1, 2, 3]'
print(repr(json.dumps(t)))  # '[4,5,6]'
print(repr(json.dumps(d)))  # '{"name":"yuan","age":18,"is_married":false,"gf":null}'

# 反序列化	將json格式字串轉為本語言支援的資料物件格式

s = '{"name":"yuan","age":18,"isMarried":False}'
#  重點:反序列化前提資料得是json格式的字串
data = json.loads(s)
print(data, type(data))

s2 = '[{"name":"yuan","age":18,"isMarried":false},{"name":"rain","age":28,"isMarried":true}]'
data2 = json.loads(s2)

print(data2,type(data2))

print(data2[1].get("name"))
日誌模組

loguru

from loguru import logger

# 寫入到檔案
# logger.remove(handle_id=None)
# rotation 配置日誌滾動記錄的機制:rotation=200MB
logger.add("mylog.log", level='ERROR', ratation="200MB")

# 基本使用,可以列印到console,也可以列印到檔案中去
logger.debug("這是一條測試日誌")
logger.info("這是一條資訊日誌")
logger.success("這是一條成功日誌")
logger.warning("這是一條警告日誌")
logger.error("這是一條錯誤日誌")
logger.critical("這是一條嚴重錯誤日誌")

# 預設輸出格式是:時間、級別、模組、行號以及日誌內容

loguru的基本配置
import sys
from loguru import logger

logger.configure(handles=[
    {
        "sink":sys.stderr, # 表示輸出到終端
        # 表示日誌格式化
        "format": "<g><b>{time:YYYY-MM-DD HH:mm:ss.SSS}</b></g> |<lvl>{level:8}</>| {name} : {module}:{line:4} | <c>mymodule</> | - <lvl>{message}</>",
        
    },
    {
        "sink": 'first.log',
        "format": "{time:YYYY-MM-DD HH:mm:ss.SSS} |{level:8}| {name} : {module}:{line:4} | mymodule | - {message}",
        "colorize": True
    },
])

logger.debug('this is debug')
logger.info('this is info')
logger.warning('this is warning')
logger.error('this is error')
logger.critical('this is critical')
logger.add("mylog.log", level="WARNING", rotation="200 B")

常見key及其描述

Key Description
time 發出日誌呼叫時的可感知的本地時間
level 用於記錄訊息的嚴重程度
name 進行日誌記錄呼叫的__name__
module 進行日誌記錄呼叫的模組
line 原始碼中的行號
message 記錄的訊息(尚未格式化)
function 進行日誌記錄呼叫的函式
thread 進行日誌記錄呼叫的執行緒名
process 進行日誌記錄呼叫的程序名
file 進行日誌記錄呼叫的檔案
extra 使用者繫結的屬性字典(參見blind())
exception 格式化異常(如果有),否則為None
elapsed 從程式開始經過的時間差

常用的顏色和樣式標籤

顏色 樣式
黑色(k) 粗體(b)
藍色(e) 暗淡(d)
青色(c) 正常(n)
綠色(g) 斜體(i)
洋紅色(m) 下劃線(u)
紅色(r) 刪除線(s)
白色(w) 反轉(v)
黃色(y) 閃爍(l)

模組與包

模組Module是指一個包含了函式、變數和類等定義的檔案,而包Package是指包含了多個模組的目錄。

模組(Module)

模組本質上就是一個py檔案

模組一共有三種:

  • python標準庫
  • 第三方模組
  • 應用程式自定義模組

模組是組織程式碼的更高階形式,提高程式碼的閱讀性和可維護性。另外,使用模組還可以避免函式名和變數名衝突。相同名字的函式和變數完全可以分別存在不同的模組中。

匯入模組

關鍵點:

  1. 模組與包的命名遵從小寫+下劃線
  2. 匯入的模組名和函式一樣是一等公民

​ 在程式語言中,”一等公民“(first-class-citizen)是指某個實體,(通常是資料型別或值)具有與其他實體相同的權利和特權。它表示在語言中,這些實體可以被像任何其他實體一樣對待,可以作為引數傳遞給函式、賦值給變數、儲存到資料結構中,以及作為函式的返回值。

  1. 使用import module匯入模組的本質就是,將module.py中的全部程式碼載入到記憶體並執行,然後將整個模組內容賦值給與模組同名的變數。
  2. 匯入同一個模組多次,Python只執行一次。
  3. 在匯入模組後,可以在模組檔案所在目錄下看到一個名為pycache的資料夾,開啟該資料夾,可以看到Python為每個模組都生成一個*.cpython-36.pyc檔案,該檔案其實是python為模組編譯生成的位元組碼,用於提升該模組的執行效率。

語法:

  1. import 模組名1 [as 別名1], 模組名2 [as 別名2], ...:使用這種語法格式的import語句,會匯入指定模組的所有成員,包括變數、函式、類等。不僅如此,當需要使用模組中的成員時,需用該模組名(或別名)作為字首,否則Python直譯器會報錯。
  2. from 模組名 import 成員名1 [as 別名1] 成員名2 [as 別名2]:使用這種語法格式的import語句,只會匯入模組中指定的成員,而不是全部成員。同時,當程式中使用該成員時,無序附加任何字首,直接使用成員名或別名即可。

__name__ == '__main__'

​ 當前執行的程式,其__name__ 的值為__main__,而匯入到當前程式中的模組,其__name__值為自己的模組名。因此,__name__ == '__main__'的作用是確保只有單獨執行該模組時,此表示式才成立,才可以進入此判斷語法,執行其中的測試程式碼;反之,如果只是作為模組匯入到其他程式檔案中,則此表示式不成立,執行其他程式時,也就不會執行該判斷語句中的測試程式碼。

包(Package)

使用模組可以有效避免變數名或函式名重名引發的衝突,

包可以避免模組名重複

包就是資料夾,該資料夾下必須存__init__.py的檔案。

包的主要作用就是組織和管理模組,使得程式碼更加結構化和可維護。包的層次結構可以是多層的,即可以包含子包(子目錄)和子模組。

導包

包本質上還是模組,因此匯入模組的語法同樣適用於匯入包。

  1. import 包名[.模組名 [as 別名]]
  2. from 包名1.包名2 import 模組名 [as 別名]
  3. from 包名1.包名2.模組名 import 成員名 [as 別名]
虛擬環境

虛擬環境(Virtual Environment)是Python中用於隔離專案依賴和執行環境的工具。

好處:

  1. 隔離依賴:每個專案可以有自己的依賴庫,不同專案之間的依賴衝突不會發生。
  2. 簡化部署:可以將專案的依賴庫和執行環境一起打包,方便在其他計算機上部署和執行。
  3. 靈活性:可以在不同的專案中使用不同的Python版本,以滿足專案的特定需求。

Python內建了vene模組,用於建立和管理虛擬環境。

  1. 建立虛擬環境:

開啟終端,進入要建立虛擬環境的目錄,執行以下命令

python3 -m venv <env_name>
  1. 啟用虛擬環境
# macOS Linux
source myenv/bin/activate
# Windows
myenv\Scripts\activate

啟用後,終端的提示符會顯示虛擬環境的名稱。

  1. 使用虛擬環境

在啟用的虛擬環境中可以安裝和管理專案所需的依賴庫,執行專案的程式碼等。所有操作都將在虛擬環境中進行,不會影響全域性Python環境和其他虛擬環境。

  1. 退出虛擬環境
deactivate
  1. 匯出和匯入依賴
# 匯出依賴到檔案
pip freeze > requirements.txt
# 從檔案中匯入依賴
pip install -r requirements.txt
軟體開發目錄規範

一個良好的目錄結構可以提高程式碼的可維護性和可擴充套件性。以下是一些常用的軟體開發目錄規範和最佳實踐:

  1. 專案根目錄:在專案的根目錄下,英包含與專案相關的檔案和資料夾,如README、LICENSE等。這是整個專案的起點。
  2. 原始碼目錄:通常將原始碼放在一個獨立的目錄中。這個目錄應該具有描述性的名稱,如src、lib或app。在原始碼目錄下,可以按照專案的模組、功能或層次結構建立子目錄。
  3. 測試目錄:測試程式碼通常位於一個獨立的目錄中。可以使用如tests、test或spec的目錄來存放單元測試、整合測試和其他測試相關的檔案。
  4. 文件目錄:為了方便團隊成員和使用者瞭解專案和程式碼的使用方式,可以建立一個文件目錄,其中包含專案文件、API文件、使用者手冊等。
  5. 配置目錄:存放專案的配置檔案,如資料庫配置、日誌配置、環境變數配置等。可以將這些配置檔案放在一個名為config或conf的目錄下。
  6. 資源目錄:存放專案所需的資原始檔,如影像、樣式表、靜態檔案等。可以將這些資原始檔放在一個名為assets或resources的目錄下。
  7. 日誌目錄:存放專案的日誌檔案,包括執行日誌、錯誤日誌等。可以將這些日誌檔案放在一個名為logs的目錄下。
  8. 其他目錄:根據專案的具體需求,可以建立其他目錄來存放特定型別的檔案,如快取目錄、備份目錄等。

一個常見的目錄規範示例:

project/
├── docs/                           # 文件目錄
│   ├── requirements/              # 需求文件
│   ├── design/                    # 設計文件
│   └── api/                       # API 文件
├── src/                            # 原始碼目錄
│   ├── app/                       # 應用程式碼
│   │   ├── models/                # 模型定義
│   │   ├── views/                 # 檢視邏輯
│   │   ├── controllers/           # 控制器邏輯
│   │   └── utils/                 # 工具函式
│   ├── config/                    # 配置檔案
│   ├── tests/                     # 測試程式碼
│   └── scripts/                   # 指令碼檔案
├── static/                        # 靜態資源目錄
│   ├── css/                       # 樣式檔案
│   ├── js/                        # JavaScript 檔案
│   ├── images/                    # 圖片檔案
│   └── fonts/                     # 字型檔案
├── templates/                     # 模板檔案目錄
├── data/                          # 資料檔案目錄
├── logs/                          # 日誌檔案目錄
├── dist/                          # 分發版本目錄
├── run.py                         # 用於啟動應用程式或執行相關操作的檔案。
├── vendor/                        # 第三方依賴目錄
├── requirements.txt               # 依賴包列表
├── README.md                      # 專案說明文件
└── LICENSE                        # 許可證檔案

上述示例中,主要包含以下目錄:

  • docs/:用於存放專案的文件,包括需求文件、設計文件和API文件等。
  • src/:存放專案的原始碼,按照模組進行組織,例如app/目錄下存放應用程式碼,config/目錄下存放配置檔案,tests/目錄下存放測試程式碼等。
  • static/:存放靜態資原始檔,例如CSS樣式檔案、JavaScript檔案、圖片檔案和字型檔案等。
  • templates/:存放模板檔案,用於生成動態內容的頁面。
  • data/:存放資料檔案,例如資料庫檔案或其他資料儲存檔案。
  • logs/:存放日誌檔案,記錄專案的執行日誌。
  • dist/:存放專案的分發版本,例如編譯後的可執行檔案或打包後的軟體包。
  • vendor/:存放第三方依賴,例如外部庫或框架。
  • requirements.txt:列出專案所需的依賴包及其版本資訊。
  • README.md:專案說明文件,包含專案的介紹、使用指南和其他相關資訊。
  • LICENSE:許可證檔案,定義專案的使用和分發條款。

相關文章