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高级编程的一个难点,只有在不断编程中自己慢慢体会才能学懂。

发布了7 篇原创文章 · 获赞 10 · 访问量 2654

猜你喜欢

转载自blog.csdn.net/weixin_41076275/article/details/104181207