十一、python的高級語法與用法


一、枚舉其實是一個類

現實世界中的“類型”,在計算機世界中如何描述?

常見的

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環境變量被記住

 

 

 
       


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM