一、枚舉其實是一個類
現實世界中的“類型”,在計算機世界中如何描述?
常見的
1)用1、2、3..等數字表示類型
2)較好的做法是用字典表示
3)最好的是使用枚舉
1 # coding=utf-8 2 from enum import Enum 3 4 5 class VIP(Enum): # 繼承Enum類 6 YELLOW = 1 # 枚舉類型建議使用大小 7 GREEN = 2 8 BLACK = 3 9 RED = 4 10 11 print(VIP.YELLOW)
1、python中,枚舉的本質是類
2、使用時需要繼承Enum類
3、類中定義一組常量,建議使用全大寫字母表示
4、數字1、2、3其實沒有意義,枚舉的意義重在標識,不在取值。
二、枚舉與普通類相比的優勢
如果不使用枚舉,如何表示類型
1)使用模塊中的全局變量
yellow=1
green=2
2) 字典
{‘yellow’:1,'green':2}
3) 普通類
class TypeDiamond():
yellow=1
green=2
缺點:
1)可變,即可以在代碼中輕易改變
2)沒有防止相同標簽的功能
現實中的‘類型’一旦定義不應該被輕易更改,但字典可以通過賦值改變類型,同樣普通類也可以輕易改變類型。
字典和普通類允許變量(類型)相同
{‘yellow’:1,'yellow:2}
在python中沒有真正的常量,在枚舉中定義的類型不能被更改,且不能取相同的標記。
1)枚舉的保護性
2)枚舉的防重性
三、枚舉類型、枚舉名稱與枚舉值
1、獲取某個枚舉標簽的值.value
2、獲取某個枚舉標簽的名字.name
3、通過枚舉標簽的名稱獲取枚舉的類型
4、枚舉可遍歷
1 # 獲取枚舉標簽的值 2 print(VIP.YELLOW.value) 3 # 獲取枚舉標簽的名字 4 print(VIP.YELLOW.name) 5 # 獲取枚舉類型 6 print(VIP.YELLOW) 7 for v in VIP: 8 print(v)
1 枚舉值
YELLOW 枚舉名稱
VIP.YELLOW 枚舉類型
四、枚舉之間的比較
枚舉支持的比較
1)等值比較
res=VIP.YELLOW==VIP.GREEN
print(res)
打印結果:False
2)身份比較
res=VIP.YELLOW is VIP.YELLOW
print(res)
打印結果:True
枚舉不支持的比較
1)名稱和值的比較
class VIP(Enum):
YELLOW = 1 # 枚舉類型建議使用大小
GREEN = 2
BLACK = 3
RED = 4
res=VIP.YELLOW ==1
print(res)
打印結果:False
2)大小比較
res=VIP.YELLOW <VIP.GREEN
print(res)
報錯:TypeError: '<' not supported between instances of 'VIP' and 'VIP'
3)枚舉類之間的比較
class VIP(Enum):
YELLOW = 1 # 枚舉類型建議使用大小
GREEN = 2
BLACK = 3
RED = 4
class VIP1(Enum):
YELLOW = 1 # 枚舉類型建議使用大小
GREEN = 2
BLACK = 3
RED = 4
res=VIP.YELLOW ==VIP1.YELLOW
print(res)
打印結果:False
五、枚舉注意事項
1、不能使用相同的標簽
2、取值可以相同,但會作為別名,不能作為獨立的枚舉類型
3、枚舉的遍歷,取值相等時,不打印(無法訪問)別名
1 # coding=utf-8 2 from enum import Enum 3 4 5 class VIP(Enum): 6 YELLOW = 1 # 枚舉類型建議使用大小 7 YELLOW2 = 1 8 BLACK = 3 9 RED = 4 10 11 for v in VIP: 12 print(v)

4、如何遍歷(訪問)別名?VIP.__members__
1 # coding=utf-8 2 from enum import Enum 3 4 5 class VIP(Enum): 6 YELLOW = 1 # 枚舉類型建議使用大小 7 YELLOW2 = 1 8 BLACK = 3 9 RED = 4 10 11 for v in VIP.__members__: 12 print(v)

六、枚舉的轉換
1、將枚舉類型轉化為數字
實際編碼過程中,推薦:在代碼中定義枚舉類型,數據庫中存儲枚舉值,通過枚舉名稱訪問數據庫中的枚舉值
if a==VIP.YELLOW:#不推薦使用a==1
print(...)
if a==VIP.GREEN:#不推薦使用a==2
print(...)
2、將數字轉化為枚舉類型
a=1
print(VIP(a))
1 # coding=utf-8 2 from enum import Enum 3 4 5 class VIP(Enum): 6 YELLOW = 1 # 枚舉類型建議使用大小 7 YELLOW2 = 1 8 BLACK = 3 9 RED = 4 10 11 a=1 12 print(VIP(a))
七、枚舉小結
1、IntEunm類
枚舉值可以是int類型,也可以是str類型,如果明確了是int類型,可以使用IntEunm類,該類限制了枚舉值只能是int
1 #coding=utf-8 2 from enum import IntEnum 3 4 5 class VIP(IntEnum): 6 YELLOW = 'a' # 枚舉類型建議使用大小 7 YELLOW2 = 1 8 BLACK = 3 9 RED = 4

2、限制別名(不能取相同值)
1 #coding=utf-8 2 from enum import IntEnum,unique 3 4 @unique 5 class VIP(IntEnum): 6 YELLOW = 1 # 枚舉類型建議使用大小 7 YELLOW2 = 1 8 BLACK = 3 9 RED = 4

3、枚舉在python中是單例模式,不能實例化
這里引入了設計模式的概念,其中單例模式是23種設計模式中的一種。
八、函數式編程、閉包導論
1、python支持函數式編程,該用的時候用
2、概念不重要,重要的是思維
3、函數:其他語言中函數是指一段可執行的代碼,並不是對象,但在python中,函數就是對象,可實例化
#coding=utf-8
def a():
pass
print(type(a))

python:一切皆對象
那么
- 函數可以賦值給變量
- 函數可作為另一個函數的參數
- 函數可作為另一個函數的返回結果
九、什么是閉包
閉包=函數+環境變量
環境變量:函數定義時用到的變量(在函數外)
1 # coding=utf-8 2 3 def curve_pre(): # 閉包 4 a = 25 # 環境變量 5 6 def curve(x): # 函數 7 return a * x * x #引用環境變量a 8 9 return curve # 返回函數 10 11 12 f = curve_pre() 13 print(f(2))
結果:100
對a重新賦值,結果如何?
1 # coding=utf-8 2 3 def curve_pre(): # 閉包 4 a = 25 # 環境變量 5 6 def curve(x): # 函數 7 return a * x * x #引用環境變量a 8 9 return curve # 返回函數 10 11 a=10 12 f=curve_pre() 13 print(f(2))
結果仍然是:100
如何獲取環境變量的值25
1 # coding=utf-8 2 3 def curve_pre(): # 閉包 4 a = 25 # 環境變量 5 6 def curve(x): # 函數 7 return a * x * x #引用環境變量a 8 9 return curve # 返回函數 10 11 f = curve_pre() 12 #獲取環境變量的值 13 print(f.__closure__[0].cell_contents)
十、一個事例看閉包
閉包的意義:保存環境,現場
局部變量不影響外部的環境變量
1 # coding=utf-8 2 3 def f1(): 4 a = 10 5 6 def f2(): 7 a = 20 8 print(a) 9 10 print(a) 11 f2() 12 print(a) 13 14 f1()
打印結果:
10
20
10
十一、閉包的經典誤區
代碼1
1 #coding=utf-8 2 3 def f1(): 4 a=10 5 def f2(): 6 a=20 #a出現在表達式的作為,會被當做局部變量 7 8 f=f1() 9 print(f.__closure__)
打印結果:
Traceback (most recent call last):
File "E:/pyClass/eleven/c11.py", line 9, in <module>
print(f.__closure__)
AttributeError: 'NoneType' object has no attribute '__closure__'
原因:
f1()不是閉包,因為沒有返回?
代碼2:加入返回
1 # coding=utf-8 2 3 def f1(): 4 a = 10 5 6 def f2(): 7 a = 20 # a出現在表達式的作為,會被當做局部變量 8 9 return f2 10 11 12 f = f1() 13 print(f.__closure__)
打印結果:None
原因:函數f2沒有返回?
代碼3:在f2中增加返回
1 # coding=utf-8 2 3 def f1(): 4 a = 10 5 6 def f2(): 7 a = 20 # a出現在表達式的作為,會被當做局部變量 8 return a 9 return f2 10 11 12 f = f1() 13 print(f.__closure__)
打印結果:None
原因:f2中沒有引用環境變量
代碼4
1 # coding=utf-8 2 3 def f1(): 4 a = 10 5 6 def f2(): 7 # a = 20 # a出現在表達式的作為,會被當做局部變量 8 return a 9 return f2 10 11 12 f = f1() 13 print(f.__closure__)
打印結果:(<cell at 0x00000000006CA5E8: int object at 0x000000001DCEB560>,)
總結
1)環境變量不能作為局部變量被賦值
2)需要返回函數
3)函數需要引用環境變量
十二、幾個問題,用閉包解決
問題:計算旅行者當前位置,假設起點x=0,每走一步,x+1
問題關鍵:保存上次結果
起點:x=0
每走一步:x+1
3步:result=3
5步:result=8
6步:result=14
方法一:非閉包
1 #coding=utf-8 2 3 origin=0 4 5 def go(step): 6 new_pos=origin+step 7 origin=new_pos 8 return origin 9 10 print(go(2)) 11 print(go(3)) 12 print(go(5))
報錯信息:
Traceback (most recent call last):
File "E:/pyClass/eleven/c12.py", line 10, in <module>
print(go(2))
File "E:/pyClass/eleven/c12.py", line 6, in go
new_pos=origin+step
UnboundLocalError: local variable 'origin' referenced before assignment
原因:第7行中,origin出現在表達式左邊,會被認為是局部變量,局部變量在6行中沒有定義就使用,系統認為是錯誤的
嘗試解決:
注釋掉第7行,不再報錯,但是打印結果
0
0
0
與預期不符
最終解決:使用global關鍵字,聲明origin為全局變量
1 #coding=utf-8 2 3 origin=0 4 def go(step): 5 global origin 6 new_pos=origin+step 7 origin=new_pos 8 return origin 9 10 print(go(2)) 11 print(go(3)) 12 print(go(5))
打印結果
2
5
10
方法二:使用閉包
1 # coding=utf-8 2 3 origin = 0 4 5 6 def factory(pos): 7 def go(step): 8 nonlocal pos # 聲明pos非局部變量 9 new_pos = pos + step 10 pos = new_pos 11 return pos 12 13 return go 14 15 16 tourist = factory(origin) 17 print("旅行者當前位置:%s" % (tourist(2))) 18 print("origin變量的值:%s" % (origin)) 19 print("環境變量的值:%s" % (tourist.__closure__[0].cell_contents)) 20 print("旅行者當前位置:%s" % (tourist(3))) 21 print("origin變量的值:%s" % (origin)) 22 print("環境變量的值:%s" % (tourist.__closure__[0].cell_contents)) 23 print("旅行者當前位置:%s" % (tourist(5))) 24 print("origin變量的值:%s" % (origin)) 25 print("環境變量的值:%s" % (tourist.__closure__[0].cell_contents))
打印結果:
旅行者當前位置:2
origin變量的值:0
環境變量的值:2
旅行者當前位置:5
origin變量的值:0
環境變量的值:5
旅行者當前位置:10
origin變量的值:0
環境變量的值:10
總結
1)origin並沒有被改變
2)pos環境變量被記住
