Python3學習(五)

–Python3新增–

9. 枚舉

實際生活中的“類”,在Python中給出了一個“枚舉”類型,用來表示它。
比如我們平時玩的大型遊戲,有各種段位之分,青銅,白銀,黃金等。我們在數據庫中可能會以序號(ID)來簡單標識,而在Python3中新增了一個“枚舉”類,就用於表示這些“類”。(Python2是沒有枚舉類的)

from enum import Enum


class Level(Enum):
    BRONZE = 1  # 青銅
    SILVER= 2  # 白銀
    GOLD= 3  # 黃金
    PLATINUM= 4  # 鉑金
    DIAMOND= 5  # 鑽石
    

之後,我們就可以直接用Level.BRONZE這種形式來表示各個類了,在繼承枚舉的類中,一般把每個常量大寫。

(1)枚舉類和普通類的區別

直觀上看起來枚舉類和普通類沒有區別,然而你打印一下print(Level.BRONZE)就發現打印結果依然是Level.BRONZE。因爲我們關注的是名,而不是值。

如果我們用字典或普通類,可以輕易地修改值,而枚舉中值是不可更改的。各位可以自己親自實驗一下,結果會報異常。而且,枚舉還防止了相同標籤的錯誤。
在這裏插入圖片描述
由於Python3中的枚舉是單例模式設計,因此無法像普通類那樣被實例化。

(2)對枚舉的簡單操作

  1. 獲取枚舉中類型的值:print(Level.DIAMOND.value)
  2. 獲取枚舉中類型標籤:print(Level.DIAMOND.name),得到的是字符串類型
  3. 遍歷枚舉:
for i in Level:
	print(i)

=======================
Level.BRONZE
Level.SILVER
Level.GOLD
Level.PLATINUM
Level.DIAMOND
  1. 比較運算:Level.GOLD == Level.DIAMOND——False
    Level.GOLD == Level.GOLD——True
    Level.GOLD is Level.GOLD——True
    Level.GOLD == 3——報錯,無法比較
    另外,枚舉類型之間是無法比較大小的,“>”和“<”是不行的。
    兩個枚舉類,Level和Level1(複製了Level中的成員)比較也是False:
    Level.GOLD == Level1.GOLD——False

幾點注意:枚舉中不同標籤的值可以設置爲相同值,但其實代表的是同一種類型,只是起了一個別名:

class Level(Enum):
	BRONZE = 1  # 青銅
	QINGTONG = 1  # 青銅的別名
	SILVER= 2  # 白銀
    GOLD= 3  # 黃金
    PLATINUM= 4  # 鉑金
    DIAMOND= 5  # 鑽石

print(Level.QINGTONG)
===============================
Level.BRONZE

且遍歷時不會打印出“QINGTONG”。如果想打印出來,大家可以自己試一下:for i in Level.__members__ :和for i in Level.__members__.item():

一個轉換:當惡魔需要將枚舉類型存儲到數據庫時,我們一般使用數字,而可以通過這種方法將數字轉換成枚舉:
a = 1
print(Level(a))
結果:Level.BRONZE

(3)enum中其他模塊

  1. IntEnum
    如果是繼承的Enum,那麼每個類型的值可以設置爲字符串,但若繼承自IntEnum,就只能爲整型。
from enum import IntEnum

class Level(IntEnum):
	GOLD = 'g'

上面這樣就會報錯。

  1. unique
    from enum import IntEnum, unique
    @unique
    class Level(IntEnum):

如果導入unique,則在定義枚舉類時,就不能出現不同類型的定義相同值了。

====================================================
現在,我們正式開始Python高級語法--------->
Python的高級語法與函數式編程有很大關係,但我自己之前並沒有接觸過函數式編程,所以歡迎大家及時提出意見和建議。

10. 閉包

Python中一切皆對象,因此,Python中的函數也屬於對象的範疇。
在其他語言中,函數定義時必須顯式地指出返回值類型,比如:
void add() {}、int main() {}而Python中完全不需要考慮這點,Python甚至可以將一個函數當作參數傳入另一個函數中,一個函數的返回值還能爲函數。一切的原因就是他們都是對象。

def add():
	pass

print(type(add))
============================
<class 'function'>

這裏打印出的是“class”,說明是一個類。
再演示一個用法,這個用法如果是C或Java,看起來會覺得非常不可思議。

def out():
	a = 1
    def inner():
        print('This is inner' + str(a))
    return inner

fun = out()
fun()
=============================
This is inner 1

百度百科對於閉包的定義是:閉包可以理解成“定義在一個函數內部的函數“。在本質上,閉包是將函數內部和函數外部連接起來的橋樑。
在這裏,閉包就是inner函數部分加上a = 1。(在學習閉包的同時要注意思考一下變量作用域

def out():
    a = 1
    def inner(b):
        print('This is inner')
        return a + b
    return inner

fun = out()
print(fun.__closure__)

==================================
(<cell at 0x00000179BD76B558: int object at 0x0000000064AD8070>,)

而下面這兩種情況並不是閉包:

# 第一種
def out():
	a = 1
	def inner(b):
		return b
	return inner

fun = out()
print(fun.__closure__)
===================================
None

# 第二種
def out():
	a = 1
	def inner(b):
		return b

fun = out()
print(fun.__closure__)
===================================
AttributeError: 'NoneType' object has no attribute '__closure__'

也就是說,閉包必須確保外層函數返回內層函數,且內層函數返回時必須用到外層函數定義的局部變量(即必須return a或者含有a的其他表達式)

說一下全局變量和局部變量注意點

看一下這段代碼:

variable = 0

def add(x):
	global variable
	temp = variable + x
	variable = temp
	return variable

print(add(3))
=============================
3

如果將第4行代碼刪除,則會報錯:
UnboundLocalError: local variable ‘variable’ referenced before assignment
這是因爲Python在執行時,函數內部的變量默認都是在內部定義的局部變量,如果不事先聲明,那麼Python將會在函數內部找變量的定義。

而在閉包中,有另一個類似於global的關鍵字:nonlocal,它聲明的變量可以記憶上一步的執行結果。在閉包內部使用。

def a(x):
	def b(y):
    	nonlocal z
        z = x * y
        ......

閉包是Python高級編程的一個難點,只有在不斷編程中自己慢慢體會才能學懂。

發佈了10 篇原創文章 · 獲贊 11 · 訪問量 2835
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章