
你好,我是阿ken
我又雙叒叕來了!
藍色、灰色為了解內容,其中藍色多為參考舉例,紅色為重點記憶,
目錄
5.1 函式概述
5.2 函式的基礎知識
5.2.1 函式的定義
5.2.2 函式的呼叫
5.3 函式的引數傳遞
5.3.1 引數的位置傳遞
5.3.2 引數的關鍵字傳遞
5.3.3 引數的默認值傳遞
5.3.4 包裹傳遞
5.3.5 解包裹傳遞
5.3.6 混合傳遞
5.4 函式的回傳值
5.5 變數作用域
5.5.1 區域變數
5.5.2 全域變數
5.6 函式的特殊形式
5.6.1 匿名函式
5.6.2 遞回函式
5.7 時間處理模塊 —— datetime
5.8 代碼抽象與模塊化設計
5.9 本文總結
快速通道:
【保姆級入門系列】阿ken教你學 Python(四)

🐮阿ken:咳咳從此刻開始,調整心情,開始上課!
5.1 函式概述
🐮阿ken:函式是組織好的、可重復使用的、用來實作單一或相關聯功能的代碼段,通過函式的名稱表示和呼叫,函式也可以看作是一段有名字的子程式,可以在需要的地方使用函式名呼叫執行,在學習本文內容之前,其實我們已經接觸過一些函式,比如輸出資訊到命令列視窗的 print() 函式、接收鍵盤輸入資訊的 input() 函式等,
函式是一種功能抽象,它可以完成特定的功能,與黑箱模型的原理一樣,黑箱模型是指所建立的模型只考慮輸入與輸出,而與程序機理無關,現實生活中,應用黑箱原理的實物有很多,比如洗衣機,對于使用者來說,大家只需要了解洗衣機的使用方法,將洗衣粉、水放入,最終得到洗干凈的衣服,這個程序是完全封閉的,對于函式外界不需要了解其內部的實作原理,只需要了解函式的輸入輸出方式即可使用,換言之,呼叫函式時以不同的引數作為輸入,執行函式后以函式的回傳值作為輸出,
函式大體可以劃分為兩類,一類是系統內置函式,它們由 Python內置函式庫提供,例如我們在前面章節中學習的 print()、input()、type()、int() 等函式;另一類是用戶根據需求定義的具有特定功能的一段代碼,自定義函式像一個具有某種特殊功能的容器 —— 將多條陳述句組成一個有名稱的代碼段,以實作具體的功能,
使用函式的好處主要體現在以下幾方面:
(1) 將程式分解成更小的塊(模塊化),
(2) 降低理解難度,提高程式質量,
(3) 減小程式體積,提高代碼可重用性,
(4) 降低了軟體開發和維護的成本,
5.2 函式的基礎知識
🐮阿ken:函式的使用可以分為函式的定義和函式的用兩部分,它只需要定義一次,便可
以無限次地被重復使用,
5.2.1 函式的定義
Python 使用 def 關鍵字定義函式,基本語法格式如下:
def 函式名([引數串列]):
['''檔案字串''']
函式體
[return陳述句]
上述語法的介紹如下:
(1) 關鍵字def:標志著函式的開始,
(2) 函式名:函式的唯一標識,其命:名方式遵循識別符號的命名規則,
(3) 引數串列:可以有零個、一個或多個引數,多個引數之間使用逗號分隔,根據引數的有無,函式分為帶參函式和無參函式,
(4) 冒號:用于標記函式體的開始,
(5) 檔案字串:用于描述函式的功能,可以省略,
(6) 函式體:函式每次呼叫時執行的代碼,由一行或多行Python陳述句構成,
(7) return陳述句:標志著函式的結束,用于將函式中的資料回傳給函式呼叫者,若函式需要回傳值,則使用 return陳述句回傳,否則 return陳述句可以省略,函式在函式體順序執行完畢后結束,
定義函式時,函式引數串列中的引數是形式引數,簡稱為“形參”,形參用來接收呼叫該函式時傳入函式的引數,注意,形參只會在函式被呼叫的時候才分配記憶體空間,一旦呼叫結束就會即刻釋放,因此,形參只在函式內部有效,
定義一個求絕對值的函式,示例如下:
def my_absolute(x):
if x >= 0:
return x
else:
return -x
以上定義的 my absolute() 函式接收引數x,使用 if-else 陳述句區分 x的正負,若 x為正數,它的絕對值就是它本身,直接回傳 x;否則回傳它的相反數,
5.2.2 函式的呼叫
函式定義好之后不會立即執行,直到被程式呼叫時才會生效,呼叫函式的方式非常簡單,一般形式如下:
函式名(引數串列)
以上形式的引數串列為會被傳遞給函式的形參、在函式執行程序中會使用的引數,這些引數是實際引數,簡稱為“實參”,實參可以是常量、變數、運算式、函式等,
呼叫上述中定義好的 my_absolute()函式,代碼如下:
my_absolute(-10.0)
以上代碼中的-10.0是實參,它將被傳遞給函式定義中的形參x,注意,函式在使用前必須已經被定義,否則解釋器會報錯,
程式執行時若遇到函式呼叫,會經歷以下流程:
(1) 程式在函式呼叫處暫停執行,
(2) 為函式傳入實參,
(3) 執行函式體中的陳述句,
(4) 程式接收函式的回傳值(可選)并繼續執行,
定義和呼叫函式 my_absolute() 的完整代碼如下:
def my absolute(x):
if x >= 0:
print(x)
else:
print(-x)
my_absolute(-10.0)
print("---程式結束---")
對以上程式進行分析: Python 解釋器讀取第 1 ~ 5 行代碼時判定此處定義了一個函式,它先將函式名和函式體存盤在記憶體空間中,但不執行;解釋器執行第 6行代碼,由于此處調了 my_absolute() 函式,程式首先暫停執行,將該函式的實參 -10.0 傳遞給形參x (x=-10.0),然后執行函式體內部的陳述句,函式體執行結束之后重新回到第 6行,最后執行第7行的列印陳述句,
5.3 函式的引數傳遞
🐮阿ken:函式的引數傳遞是指將實參傳遞給形參的程序,Python 中的函式支持以多種方式傳遞引數,包括位置傳遞、關鍵字傳遞、默認值傳遞、包裹傳遞、解包裹傳遞以及混合傳遞,本節將針對函式不同的傳參方式進行講解,
5.3.1 引數的位置傳遞
呼叫函式時,默認按照位置順序將對應的實參傳遞給形參,即將第 1個實參分配給第 1個形參,第 2個實參分配給第 2個形參,以此類推,
假設有個用于判斷三角形是否為直角三角形的 is_triangle() 函式, 該函式的定義
具體如下:
def is_triangle(a, b, c):
if a*a + b*b == c*c or a*a + c*c == b*b
or b * b + c * a:
print("是直角三角形")
else:
print("不是直角三角形")
由以上定義可知,is_triangle() 函式需要接收 3個表示三角形各邊邊長 (大于0)的整型引數,呼叫 is_triangle()函式, 傳入 3個整數,代碼如下:
is_triangle(1, 2, 3)
以上代碼中的第 1 個實參 "1 " 會被賦給第 1個形參a,第 2個實參 " 2 " 會被賦給第 2個形參b,第 3個實參 3會被賦給第 3個形參c,
通過位置傳遞方式傳參時實參的個數必須與形參的個數保持一致,否則程式會出現例外,
5.3.2 引數的關鍵字傳遞
🐮阿ken:如果函式中形參的數目過多,開發者很難記住每個引數的作用,這時可以使用關鍵字方式傳遞引數,關鍵字傳遞通過 ” 形參變數名 = 實參 " 的形式將形參與實參關聯,根據形參的名稱進行引數傳遞、它允許實參和形參的順序不一致,
例如,有一個構建URL格式序符中的函式 makeup_url(),該函式有兩個引數:protocal和 address,分別用于接收協議頭和主機地址,它的定義如下所示:
def makeup_url(protocal, address):
print("URL = {}: //{}".format(protocal, address))
通過關鍵字方式傳參時,可以使用如下兩種形式:
makeup_url(protocal='http', address='www.baidu.com')
makeup_url(address='www.baidu.com',protocal='http')
這時,我們無須再關心定義函式時引數的順序,直接在傳參時指定對應的名稱即可,
5.3.3 引數的默認值傳遞
函式在定義時可以給每個引數指定默認值,基本形式為:函式名(引數 = 默認值),這樣在呼叫時既可以給帶有默認值的引數重新賦值,也可以省略相應的實參,使用引數的默認值,
例如,fun(a=1,b=2,c=3)函式中分別為3個引數a、b、c設定了默認值1、2、3,使用fn(a=7,b=8)呼叫函式,此時 a和 b的值7和8將覆寫默認值1和2,但是引數 c保持不變,仍然使用默認值3,默認值傳遞方式并不要求實參與形參的數量相等,
定義 makeup_url() 函式時為引數 protocal 設定默認值,如下所示:
def makeup_url(address, protocal="http"):
print("URL = {}: //{}" .format(protocal, address))
注意,若帶有默認值的引數與必選引數同時存在,則帶有默認值的引數必須位于必選引數的后面,
呼叫 makeup_url() 函式可以使用如下兩種形式:
makeup_url(address='www.itcast.cn')
makeup_url(protocal="https",address='www.baidu.com')
使用第 1種形式呼叫函式時,因為沒有傳值給protocal引數,所以默認會使用該引數的默認值“http";使用第 2種形式呼叫函式時,因為同時傳值給 protocal和 address引數、所以 address引數的新值會替換該引數的默認值,
5.3.4 包裹傳遞
若定義函式時不確定需要傳遞多少個引數,可以使用包裹傳遞,包裹傳遞的關鍵在于定義函式時,在相應的引數前添加 “*" 或 ”**":若在某個引數名稱的前面加 “*",可以元組形式為該引數傳入一組值;若在某個引數名稱前加 “**”,可以關鍵字傳遞形式為該引數傳入一組值,
例如,定義以 “*” 包裹形參 args 的函式test():
def test(*args):
print(args)
呼叫以上定義的 test()函式時可以傳入多個引數,比如傳入 5個引數:
test(1,2,3,4,5)
(1,2,3,4,5)
由以上運行結果可知,test()的引數 args接收了一個包含 5個元素的元組,
例如,定義帶有 “**” 包裹形參 kwargs 的函式 test():
def test(**kwargs):
print(kwargs)
呼叫 test()函式時能夠以關鍵字傳遞的方式傳遞多個引數,例如:
test(a=1, b=2,c=3,d=4,e=5)
{'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e':5}
由以上運行結果可知,test()的引數 args接收了一個包含 5個鍵值對的字典,
5.3.5 解包裹傳遞
在呼叫函式時,若函式接收的實參為元組或字典型別,可以使用 “*” 和 “**” 對函式引數解包裹,將實參拆分為多個值,并按照位置傳遞方式或關鍵字傳遞方式將值賦給各個形參,
(1) 元組解包裹
下面來看一個對元組解包裹的示例,代碼如下:
def func(a, b, c):
print(a, b, c)
args = (1, 2, 3)
func(*args)
以上代碼先定義了需要接收 3個引數的 func() 函式,然后呼叫 func()函式并向該函式傳入了一個包含 3個元素的元組 args,由于元組 args的前面添加了 “*”,Python 對 kwargs 進行解包裹操作,將 args元組中的 3 個元素拆分為 3個值,并分別按順序賦值給形參a、b、c,
(2) 字典解包裹
下面來看一下對字典解包裹的示例,代碼如下:
kwargs = {'a':1, 'b': 2,'c':3}
func(**kwargs)
以上代碼呼叫了 func() 函式, 并向該函式中傳入了一個包含 3 個鍵值對的字典 kwargs,由于字典 kwargs 的前面添加了 "**",Python 對 kwargs 進行解包裹操作,將字典 kwargs 中的 3 個鍵值對拆分為 3 個值,并分別按引數名稱賦值給形參a、b、c,
5.3.6 混合傳遞
前面介紹了函式引數的若干種傳遞方式,這些方式在呼叫函式時可以混合使用,但是在使用的程序中要注意前后的順序,混合使用的基本原則如下:
(1) 先按照引數的位置傳遞,
(2) 再按照引數的關鍵字傳遞,
(3) 最后按包裹的形式傳遞,
例如,定義一個函式,該函式包含必選引數、默認引數、可變引數和關鍵字引數:
def func(a,b,c=0, *args, **kw):
print ('a =',a,'b =', b, 'c =', c, 'args =', args, 'kw =',kw)
在呼叫 func()函式時,Python 解釋器按斬訓合使用的原則傳遞引數,呼叫函式的示例如下:
func(1,2) # 按位置傳遞方式將1、2賦值給a、b,c采用默認值0
a=1 b=2 c=0 args = () kw = {}
func(1, 2, c=3) # 按位置傳遞方式將1、2賦值給a、b,將3賦值給c
a=1 b=2 c=3 args = () kw = {}
func(1, 2, 3, 'a', 'b')
a=1 b=2 c=3 args = ('a', 'b') kw = {}
func(1, 2, 3, 'a', 'b', x=99)
a=1 b=2 c=3 args = ('a', 'b') kw = {'x': 99}
呼叫 func()函式時傳入一個元組和字典,可以通過解包裹的形式傳遞引數,例如:
args = (1, 2, 3, 4)
kw = {'x': 99}
func(*args, **kw)
a = 1 b = 2 c = 3 args = (4,) kw= {'x': 99}
使用混合傳遞時有兩點需要注意:
(1) 若定義函式時引數有默認值,則帶有默認值的引數必須跟在必選引數的后面,
(2) 若呼叫函式時需要混合使用位置傳遞和關鍵字傳遞,則必選引數要出現在關鍵字引數之前,
5.4 函式的回傳值
函式中的 return 陳述句是可選項,可以出現在函式體的任何位置,它的作用是結束當前函式,將程式回傳到函式被呼叫的位置繼續執行,同時將函式中的資料回傳給主程式,
撰寫含有自定義函式 is_capital()的程式,實作判斷鍵盤輸入的字串是否以大寫字母開頭的功能,代碼如下:
def is capital(words):
if ord("A")<=ord(words[0])<=ord("z"):
return '首字母是大寫的'
else:
return '首字母不是大寫的'
result = is_capital("othon") # 將函式回傳的結果交給變數
print(result)
執行程式,程式輸出的結果:
首字母是大寫的
游戲專案通過坐標控制角色位置,角色坐標由 x和 y兩個值決定,這要求與位置相關的函式能夠同時回傳 x和 y兩個值,函式可以回傳兩個值嗎? 答案是肯定的,不僅如此,Python 函式中的 return也可以回傳多個值,當函式使用 return陳述句回傳多個值時,這些值將以元組形式保存,
例如,定義一個控制游戲角色移動的函式 move(),使用 return陳述句回傳反映角色當前位置的 nx 和 ny,代碼如下:
02 control game role. py
import math
def move(x, y, step, angle=0)
nx=x+ step math cos(angle
y =y- step math sin (angle)
return nx, ny
#回傳多個值
result move (100, 100, 60, math. pi/6)
#實際上回傳的是一個元組
print(result)
以上程式定義了 move()函式、使用變數 result 接收了 move()函式回傳的計算結果并將結果列印,列印資訊如下:
(151.96152422706632, 70.0)
由以上結果可知,函式回傳的其實是一個包含兩個元素的元組,
5.5 變數作用域
Python 變數并不是在哪個位置都可以訪問的,具體的訪問權限取決于變數定義的位置,其所處的有效范圍視為變數的作用域,根據作用域的不同,變數可以劃分為區域變數和全域變數,
5.5.1 區域變數
在函式內部定義的變數稱為區域變數,區域變數只能在定義它的函式內部使用,例如,定義一個包含區域變數 count 的函式 test(),在函式的內部和外部分別訪問變數 count,代碼如下:
def test():
count = 0 # 區域變數
print(count) # 函式內部訪問區域變數
test()
print(count) # 函式外部訪問區域變數
執行程式,程式執行的結果如下:
0
Traceback (most recent call last):
File "C:/Users/admin/PycharmProjects/測驗/func.py", line 6, in <module>
print(count)
NameError: name 'count' is not defined
以上程式在列印 count的值之后又列印了錯誤資訊 "name 'count' is not defined“,由此可知,函式中定義的變數在函式內部可使用,但無法在函式外部使用,
區域變數的作用域僅限于定義它的代碼段內,在同一個作用域內,不允許出現同名的變數,
5.5.2 全域變數
全域變數是指在函式之外定義的變數,它在程式的整個運行周期內都占用存盤單元,默認情況下,函式的內部只能獲取全域變數,而不能修改全域變數的值,例如,將前面定義的 test()函式進行調整,如下所示:
count = 10 # 全域變數
def test():
count = 11 # 實際上定義了區域變數, 區域變數與全域變數重名
print(count)
test()
print(count)
以上代碼中首先在 test() 函式外定義了一個全域變數 count,其次在該函式的內部嘗試為 count 重新賦值,然后在函式的內部訪問了變數 count,最后在執行完函式后訪問變數 count,
執行程式,程式執行的結果如下:
11
10
從以上結果可知,程式在函式 test() 內部訪問的變數 count為 1,函式外部訪問的變數為10,也就是說,函式的內部并沒有修改全域變數的值,而是定義了一個與全域變數同名的區域變數,
在函式內部若要修改全域變數的值,需要提前使用保留字 global進行宣告,語法格式如下:
global 全域變數
對以上定義的 test() 函式再次進行調整,在該函式中對全域變數 count進行修改,具體代碼如下所示:
count = 10 # 全域變數
def test():
global count # 宣告 count為全域變數
count += 10 # 函式內修改 count變數
print(count)
test()
print(count)
以上代碼首先定義了變數 count并賦值為10,其次在 test() 函式內部使用 global保留字宣告 count為全域變數,然后重新給 count變數賦值并將其輸出,最后在函式執行完以后再次輸出,
執行程式,程式執行的結果如下:
20
20
觀察執行結果,程式在函式內部和外部獲得的變數 count的值均為20,由此可知,在函式內部使用關鍵字 global對全域變數進行宣告后,函式中對全域變數進行的修改在整個程式中都有效,
多學一招:LEGB法則
Python 中的作用域大致可以分為以下 4種
(1) L(local):區域作用域,
(2) E(enclosing):嵌套作用域,
(3) G(global):全域作用域,
(4) B(built-in):內置作用域,
基于 LEGB 法則,搜索變數名的優先級是:區域作用域>嵌套作用域>全域作用域>內置作用域,當函式中使用了未確定的變數名時,Python 會按照優先級依次搜索 4個作用域,以此來確定該變數名的意義,首先搜索區域作用域 (L),其次是上一層函式的嵌套作用域 (E),然后是全域作用域 (G),最后是內置作用域(B),按照 LEGB原則查找變數,在某個區域內若找到變數,則停止繼續查找;若一直沒有找到變數,則直接引發 Name Error 例外,
5.6 函式的特殊形式
🐮阿ken:除了前面介紹的普通函式之外,Python 還有兩種具有特殊形式的函式:匿名函式和遞回函式,
5.6.1 匿名函式
匿名函式是一類無須定義識別符號的函式,它與普通函式一樣可以在程式的任何位置使用,但是在定義時被嚴格限定為單一運算式,Python 中使用 lambda關鍵字定義匿名函式,它的語法格式如下:
lambda <形式引數串列>: <運算式>
與普通函式相比,匿名函式的體積更小,功能更單一,它只是一個為簡單任務服務的物件,它們的主要區別如下:
(1) 普通函式在定義時有名稱,而匿名函式沒有名稱,
(2) 普通函式的函式體中包含有多條陳述句,而匿名函式的函式體只能是一個運算式,
(3) 普通函式可以實作比較復雜的功能,而匿名函式可實作的功能比較簡單,
(4) 普通函式能被其他程式使用,而匿名函式不能被其他程式使用,
定義好的匿名函式不能直接使用,最好使用一個變數保存它,以便后期可以隨時使用這個函式,例如,定義一個計算數值平方的匿名函式,并賦值給一個變數:
temp = lambda x : pow(x, 2) # 定義匿名函式, 它回傳的函式物件賦值給變數 temp
此時,變數 temp可以作為匿名函式的臨時名稱來呼叫函式,示例如下:
temp(10)
100
5.6.2 遞回函式
遞回是指函式對自身的呼叫,它可以分為以下兩個階段:
(1) 遞推:遞回本次的執行都基于上一次的運算結果,
(2) 回溯:遇到終止條件時,則沿著遞推往回一級一級地把值回傳來,
遞回函式通常用于解決結構相似的問題,其基本的實作思路是將一個復雜的問題轉化成若干個子問題,子問題的形式和結構與原問題相似,求出子問題的解之后根據遞回關系可以獲得原問題的解,遞回有以下兩個基本要素:
(1) 基例:子問題的最小規模,用于確定遞回何時終止,也稱為遞回出口,
(2) 遞回模式:將復雜問題分解成若干子問題的基礎結構,也稱為遞回體,
遞回函式的一般形式如下:
def 函式名稱 (引數串列):
if 基例:
return 基例結果
else:
return 遞回體
由于每次呼叫函式都會占用計算機的一部分記憶體,若遞回函式未提供基例,函式執行后會回傳 " 超過最大遞回深度 " 的錯誤資訊,
遞回最經典的應用就是階乘,例如,求n的階乘,數學中使用函式 fact(n)表示:
fact(n)=n!=1*2*3*…*(n-1)*n=fact(n-1)*n
在程式中定義 fact()函式實作階乘計算,可以寫成如下形式:
def fact(n):
if n == 1: # 基例
return 1
else:
return fact(n-1)*n # 遞回體
fact(n) 是一個遞回函式,當n大于1時,fact() 函式以 n-1作為引數重復呼叫自身直到 n為1時呼叫結束,開始通過回溯得出每層函式呼叫的結果,最后回傳計算結果,
[回頭補一個遞回程序表]
斐波那契數列也是遞回的一個經典案例,斐波那契數列又稱黃金分割數列,這個數列從第 3項開始,它的每一項都等于前兩項的和,在數學上,斐波納契數列以遞推的方式定義,具體如下所示:
F(1)=1, F(2)=1, F(n)=F(n-1)+F(n-2) (n>=3, n∈N*)
根據以上定義,斐波那契數列的前 9項依次為:1、1、2、3、5、8、13、21、34,
斐波那契數列由數學家列昂納多·斐波那契以兔子繁殖為例子而引入,故又稱為 " 兔子數列 ",兔子繁殖的故事是這樣的,一般兔子在出生兩個月后就有繁殖能力,對兔子每個月能生出一對小兔子來,如果所有的兔子都不死,那么一年以后一共有多少對兔子?
第1個月, 兔子沒有繁殖能力,此時兔子的總數量為1對,
第2個月, 免子擁有了繁殖能力,生下一對小免子,此時兔子的總數量為2對,
第3個月, 兔子又生下一對小兔子,而小兔子沒有繁殖能力,此時兔子的總數量為3對,
依此類推,可以得知,經歷 0或 1個月份后,兔子的總數量均為1,之后每經歷一個月份,兔子的總數量為前兩個月份的數量和,例如,經過 3個月時兔子的總數量為1+2=3,經過 4個月時兔子的總數量為 2+3=5,經歷 5個月時兔子的總數量為 3+5=8,
使用代碼實作計算兔子數列的函式,具體如下所示:
def rabbit(month):
if month <= 1:
return 1
else:
return rabbit(month-1) + rabbit(month-2)
以上代碼定義了一個遞回函式 rabbit(),該函式接收一個代表經歷的月份的引數 month,并在代碼段中使用 if-else 陳述句區分了 1月份和其他月份的不同,若是經過了一個月,則回傳總數量為1,代表著遞回函式的出口,若是經過了N (大于1)個月,則會重復呼叫 rabbit()函式,回傳 rabbit(month-2) 與 rabbit(month-1) 的和,
在解釋器中定義 rabbit()函式,并使用以下陳述句呼叫該函式,可計算出經過一年以后,兔子的總數量為:
rabbit(12)
233
5.7 時間處理模塊 —— datetime
🐮阿ken:Python 提供了專門操作日期與時間的 datetime模塊,該模塊提供了很多處理日期與時間的方法,使用這些方法可以從系統中獲得時間,并以用戶選擇的格式進行輸出,
datetime 模塊以格林尼治時間為基礎,將每天用 3600×24 秒精準定義, datetime 模塊中定義了兩個常量:datetime.MINYEAR 和 datetime.MAXYEAR,這兩個常量分別表示最小年份 (1)和最大年份 (9999) ;datetime 模塊還定義了 6個核心的類:
datetime 模塊的核心類:
| 類名 | 說明 |
| date | 表示具體日期,精確到天 |
| time | 表示具體的時間,可精確到微秒 |
| datetime | 表示具體的日期時間,可以理解為 date和 time |
| timedelta | 表示具體的時間差 |
| tzinfo | 表示日期與時間的時區 |
| timezone | tzinfo 抽象基類,表示與 UTC的固定偏移量 |
上表中的前 3個類最為常見,接下來分別對這 3個類中的常用方法進行介紹:
1. date類
date 類表示理想化日歷中的日期,由年、月和日組成,比如 1998年1月1日,最簡單的創建日期的方式是使用 date類的構造方法,該函式的語法格式如下:
class date(year, month, day)
以上函式中每個引數都只能是整型,它們的含義如下:
(1) year:指定的年份,MINYEAR ≤ year ≤ MAXYEAR,
(2) month:指定的月份,1 ≤ month ≤ 12,
(3) day:指定的日期,1 ≤ day ≤ 給定月份和年份中的天數,
例如,創建一個表示 2019年1月4日的日期物件,代碼如下所示:
from datetime import date
date(2019, 1, 4)
date time.date(2019, 1, 4)
2. time 類
time 類是 datetime 模塊中用于處理時間的類,表示一天中的(本地)時間,由時、分、秒以及微秒組成,比如 12點 0分 0秒,通過 time類的構造方法可以創建一個時間物件,該函式的語法格式如下:
datetime.time(hour=0, minute=0, second=0, microsecond=0)
以上函式中每個引數的含義如下:
(1) hour:指定的小時,0 ≤ hour < 24,
(2) minute:指定的分鐘數,0 ≤ minute < 60,
(3) second:指定的秒數,0 ≤ second < 60,
(4) microsecond:指定的微秒數,0 ≤ microsecond < 1 000 000,
例如,創建一個表示 12時 10分 30秒的時間物件,代碼如下所示:
from datetime import time
time(12, 10, 30)
datetime.time(12, 10, 30)
3. datetime 類
datetime 類可以視為 date類與 time類的結合體,它可以同時表示日期和時間,例如 1970年1月1日0時0分0秒,創建 datetime物件的常見方法有以下4個:
(1) datetime():datetime 類的構造方法,用于構造一個指定日期和時間的 datetime物件,可精確到微秒,
(2) today():獲取一個表示本地當前日期和時間的 datetime物件,
(3) now():獲取一個表示當前時區日期和時間的 datetime物件,
(4) utcnow():獲取當前日期和時間對應的 UTC (世界標準時間)物件,
通過 datetime()方法可以直接構造一個日期時間物件,該方法中引數的含義與 date() 和time() 方法中引數的含義相同,此處不再贅述,例如,創建一個表示 2018年 6月 1日 12點 12分 30秒 50微秒的物件,如下所示:
from datetime import datetime
datetime(2018, 6, 1, 12, 12, 30, 50)
datetime.datetime(2018, 6, 1, 12, 12, 30, 50)
通過 today()方法獲取本地當前的日期與時間,時間會精確到微秒,如下所示:
datetime.today()
datetime.datetime(2019, 1, 4, 14, 33, 8, 248797)
通過 now()方法可以獲取指定時區的日期和時間,時間同樣會精確到微秒,若不指定時區,回傳本地的日期與時間,作用等同于 today()方法,例如,獲取本地當前的日期與時間,如下所示:
datetime.now()
datetime.datetime(2019, 1, 4, 14, 39, 45, 780534)
通過 utcnow() 方法可以獲取當前日期和時間對應的 UTC時間 (世界標準時間),時間仍然會精確到微秒,例如,今天的日期是 2019年 1月 4日,所處東八區的具體時間是 14時 45分,當前所對應的世界標準時間為:
datetime.utcnow()
datetime.datetime(2019, 1, 4, 6, 45, 9, 505050)
創建好 datetime物件以后,可以使用物件的屬性和方法進一步控制時間的輸出格式,
datetime類的常用屬性
| 屬性 | 說明 |
| year | 回傳日期包含的年份 |
| month | 回傳日期包含的月份 |
| day | 回傳日期包含的日 |
| hour | 回傳日期包含的小時 |
| minute | 回傳日期包含的分鐘 |
| second | 回傳日期包含的秒鐘 |
| microsecond | 回傳日期包含的微秒 |
此外,datetime 類中還提供了常用的格式化日期字串的 strftime() 方法,可以使用任何通用的格式輸出時間,
strftime() 方法控制符
| 格式控制符 | 說明 |
| %Y | 四位數的年份表示,取值范圍為0001 ~ 9999 |
| %m | 月份(01 ~ 12) |
| %d | 月內中的一天 |
| %B | 本地完整的月份名稱,比如 January |
| %b | 本地簡化的月份名稱,比如 Jan |
| %a | 本地簡化的周日期 |
| %A | 本地完整周日期 |
| %H | 24小時制小時數(0 ~ 23) |
| %I | 12小時制小時數(01 ~ 12) |
| %p | 本地 A.M. 或 P.M. 等價符 |
| %M | 分鐘數(00 ~ 59) |
| %S | 秒(00 ~ 59) |
例如,創建一個 datetime物件,以形如 " 時-分-秒 年-月-日 " 的格式進行輸出,代碼如下:
date_time = datetime.now()
date_time
datetime.datetime(2019, 1, 4, 17, 15, 58, 255314)
date_time, strftime("%H-%M-%S %Y-%m-%d") # 回傳格式化日期
'17-15-58 2019-01-04'
多學一招:格林尼治時間
我們平時所使用的時間,是以太陽在天空中的方位作標準來計量的,每當太陽轉
到夭球子午線的時刻,就是當地正午12時,由于地球自轉,地球上不同地點看到太
陽通過天球子午線的時刻是不一樣的,例如,當英國倫敦是中午12點時,北京正值
晚上7時45分,上海則是晚上8時06分,
為了使用方便,人們把全球劃分成24個時區,毎個時區跨經度為15度,英國原
格林尼治天文臺所在的時區叫作零時區,包括西經7.5度到東經7.5度范圍內的地區,
在這個時區里的居民都采用原格林尼治天文臺的時間,零時區以東第一個時區,叫作
東一區,從東絲75度到225度,是用東經15度的時間作標準的,再往東順次是東
區、東三區……直到東十二區,每跨過一個時區,時間正好相差1小時,同樣地,
零時區以西順次劃分為西一區、西二區……一直到西十二區(西十二區就是東十二
區)世界各地都包括在這24個時區里,每個時區的時間是統一的,稱為區時,
中國位于格林尼治東面,使用的是東經120度的標準時間,屬于東八區,我們日
常所說的“北京時間**點”就是東八區的標準時間,
5.8 代碼抽象與模塊化設計
函式的特點主要體現在兩個方面:代碼抽象和模塊化設計,關于它們的介紹分別如下:
1. 代碼抽象
程式由一系列的代碼組成,若代碼無序且無組織,不僅不利于開發人員的閱讀與理解,后期也很難開發與維護,為了形成易于理解的結構,避免撰寫出面條式代碼 (非結構化和難以維護的源代碼),需要對代碼進行抽象,通常采用函式和物件兩種抽象方式抽象代碼,
函式將一段代碼封裝起來并對其命名后供其他程式呼叫,函式的優點有很多,最直接的優點就是實作代碼復用,函式定義之后可以在程式中多次被呼叫,從而避免重復撰寫具有相同功能的代碼,
物件是程式的一種高級抽象方式,它將一段代碼組織成更高級別的類,類是一組具有相同屬性和方法的物件集合,描述了屬于該物件的所有性質,物件存在于現實世界中,比如大學生、汽車、空調等,物件包括描述特征的屬性和描述行為的方法,例如,大學生是—個物件,姓名、年齡等是屬性,跑步、學習、思考等是方法,
函式和物件分別是面向程序編程思想和面向物件編程思想的核心,面向程序是種以程序描述為中心的編程方式,它要求開發人員列出解決問題所需要的步驟,然后用函式將這些步驟逐個實作,使用時依次建立呼叫函式的陳述句即可;面向物件編程是一種組織程式的新型思維方式,這種思維方式會將資料和操作封裝到一起,組成一個相互依存、不可分離的整體 ——物件,
面向物件程式設計的焦點不再是程序,而是物件及物件間的關系,此種思想提取同一型別事物的共性構造出類,在類中設定這一類事物的共同屬性,為類定義與外界發生關系的介面 ——方法,
面向程序與面向物件是兩種不同的編程方式,它們的抽象級別有所不同,所有能通過面向物件編程實作的功能都可以采用面向程序完成,兩者在解決問題上并不存在優劣之分,具體采用哪種方式取決于開發要求,一般在撰寫大規模程式時建議采用面向對
象的編程方式,
Python 語言同時支持面向物件和面向程序兩種編程方式,本系列文采用面向程序的方
式撰寫程式,但 Python3 內部代碼全部采用面向物件方式實作,為降低讀者的理解難
度,阿ken 在講解和使用 Python模塊時會涉及面向物件 (呼叫類的函式創建物件、調
用物件的方法操作物件)
2. 模塊化設計
模塊化設計是指通過函式或物件的封裝功能將程式劃分成主程式、子程式、子程
序與子程式間關系的表達,它體現的是分而治之的思想,
針對復雜問題的求解所采用的模塊劃分通常是從功能的角度進行的,劃分后的模塊要具備 " 相對獨立、功能單一 " 的特征,也就是說,一個好的模塊必須具有高度的獨立性和較強的功能,在實際應用中,通常會用如下兩個指標從不同的角度對模塊的劃分情況加以度量,
(1) 內聚度:是對模塊內各元素之間相互依賴性大小的度量,內聚度越大,模塊內各元素之間聯系越緊密,其功能越強;反之,低內聚模塊內各元素的關系較為松散,
(2) 耦合度:是對模塊之間相互依賴程度的度量,耦合度越低,模塊的相對獨立性越大;耦合性越高,一個模塊受其他模塊的影響越大,
模塊劃分時應當盡可能降低不同模塊間的關聯,提升單一模塊自身的功能性,做
到 " 高內聚、低耦合 ",
采用模塊結構設計程式的好處在于:整個程式結構清晰,易于分別撰寫與除錯,便于維護與呼叫,并利于程式功能的進一步擴充與完善,
5.9 本文總結
本章首先介紹了函式的概念、定義和呼叫,其次介紹了函式引數傳遞的幾種方式,然后介紹了變數作用域和兩個具有特殊形式的函式:匿名函式和遞回函式,之后介紹了日期時間處理模塊 datetime,最后介紹了代碼重用與模塊化設計的思想,通過對本文的學習,讀者應能夠理解函式式編程的優越性,可以按照需求靈活定義函式,

后來你常常會遇到更優秀的人
可能也會跟我一樣經常感覺自己是個 loser
但后來想起來Kobe的一句話:如果一定有人會贏,那個人為什么不能是我呢?
而今故人已逝,隨著年紀增長,我也漸漸懂了這句話背后的艱辛和努力
也常常用這句話勉勵尚在低谷階段的自己
不管怎樣
我一定要贏
Peace
快速通道:
【保姆級入門系列】阿ken教你學 Python(四)
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/286636.html
標籤:其他
