九、Python的高级语法和用法

9 python的高级语法和用法

9.1 枚举

9.1.1 初识枚举

python中所有枚举类型都是enum模块下Enum类的子类, 在使用前,要导入相应的模块和类:

1
2
3
4
5
6
7
8
9
10
11
from enum import Enum

class VIP(Enum):
# 枚举中的标识最好全部使用大写
CAT = 1
DOG = 2
ANT = 3
# 枚举的意义重在标签而不在于数值
# 这样打印出来的结果也更符合实际意义
print(VIP.CAT)
# VIP.CAT

9.1.2 枚举的优点及枚举的类型、名称、值

如果用字典(dict)或者一个类来表示枚举值,会有以下缺点:
1.可变 ; 2.没有防止相同标签的功能
python中Enum及其子类,枚举类型的值是不能更改的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from enum import Enum

class VIP(Enum):
# 枚举中的标识最好全部使用大写
CAT = 1
DOG = 2
ANT = 3
#CAT = 4 #枚举标签不能重复
PAN = 1
# 枚举的意义重在标签而不在于数值
# 这样打印出来的结果也更符合实际意义
print(VIP.CAT)
# VIP.CAT = 2 # 值不能改变
print(type(VIP.CAT)) # <enum 'VIP'>
print(VIP.CAT) # 枚举的类型:VIP.CAT
print(VIP.CAT.name) # 枚举的名称:CAT
print(VIP.CAT.value) # 枚举的值:1
print(VIP['CAT'])

for v in VIP:
print(v) #VIP.ANT <enum 'VIP'>
print(type(v))

9.1.3 枚举的比较

a.枚举类型之间可以进行等值比较(==),但直接和数值比较会返 回False,如:VIP.GREEN == 2 返回False ;
b.枚举类型之间不支持大小比较操作符(>、<)的;
c.枚举类型可以进行身份比较(is),如:VIP.GREEN is VIP.GREEN 返回 True;
d.不同枚举类中的枚举类型进行比较都会返回False;

9.1.4 枚举的注意事项(值重复)

见代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from enum import Enum
class VIP(Enum):
BLACK = 1
YELLOW = 2
RED = 3
BLUE = 1

# 当枚举类 BLUE与BLACK 值相等时
# 最好把BLUE改为BLACK的别名
print(VIP.BLUE) # 输出结果为:VIP.BLACK
print('=====')
for v in VIP:
print(v)#并不会打印出BLUE
print('====')
for v in VIP.__members__:
print(v)
print('=====')
for v in VIP.__members__.items():
print(v)

输出结果为:

9.1.5 枚举的转换

可过数值(value)获取对应枚举类型:

1
2
3
4
5
6
7
8
9
10
11
from enum import Enum
# 枚举转换;将枚举类型存储在数据库时,尽量存储value
class VIP(Enum):
BLACK = 1
RED = 2
PINK = 3

print(VIP.BLACK.name)
# BLACK
print(VIP(1))
# VIP.BLACK

9.1.6 枚举小结

a.使用IntEnum时,枚举的值只能为number,不能为字符串(str);
b.在枚举类前加上 unique 装饰器后,枚举的值不能重复,只能唯一;

1
2
3
4
5
6
7
8
9
10
11
12
13
from enum import Enum
from enum import IntEnum,unique

# 枚举是一种单例模式,不能实例化
# (23种设计模式,遇到再去学习)
# 定义一个value不重复,且只能为数字的枚举类型
@unique
class VIP(IntEnum):
CAT = 1
DOG = 2.2
ANT = 3
print(VIP.CAT.name)
# CAT

9.2 Python高阶知识点

a. 业务逻辑的开发者,不考虑太多封装性:高阶内容用途不大;
b. 包、类库的开发者(开发了大量业务逻辑):高阶内容很重要;
c. python中一切皆对象,函数也是对象;
python中的函数不仅可以赋值给变量,还可以作为另外一个函数的参数传递,也可以作为另外一个函数的返回结果。

9.2.1 闭包

闭包是函数式编程思想的一种应用

a. python中闭包的定义:由函数及其在定义时外部的环境变量(不能是全局变量)构成的整体;
python在函数内部还可以定义函数,但该函数作用域只在外部函数内部有效,除非作为外部函数的返 回值被返回,在外部函数的外部用一个变量接收后就可以调用它了;
b. 闭包 = 函数 + 环境变量(函数定义时候);
c. f.closure返回一个闭包的环境变量,此时环境变量作为一个对象;
f.closure[0].cell_contents 返回环境变量的具体值.
代码演示如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 闭包演示
def fruit():
a = 2
def light(f):
print('This fruir is ' + a*f)
return light
# 调用fruit(),并用变量s接收其返回的函数
s = fruit()
# 调用
s('orange') #This fruir is orangeorange

#打印闭包的环境变量
print(s.__closure__)
# 为一个对象(<cell at 0x007111F0: int object at 0x1E1FD440>,)

#打印出闭包环境变量的具体值
print(s.__closure__[0].cell_contents) # 2

```
d. 闭包的意义在于保存了一个环境;尤其是函数中调用函数时,如果没有闭包,很容易被外部变量所影响。
e. 闭包必须满足2个条件,函数嵌套函数,并且内部函数需要引用父函数的变量;只有闭包才有__closure__属性:

{% asset_img close-package.pngg 闭包常见误区 %}

##### 一个容易犯的关于变量认识上的错误:
``` bash
origin = 0
def go(step):
new_pos = origin + step
origin = new_pos
return origin

此时会报错说origin在函数内未被定义,而把origin = new_pos去掉之后则不会报错。
a. 关于两者的不同,在一般情况下,根据变量的作用域链,origin在函数内未被定义时会去找上一级的同名变量。但是一旦在函数内origin出现了赋值语句的左侧,则会被认为是函数内被定义,成为了一个局部变量,不会再去寻找上一级,结果执行语句时就报错了。
b. 如果想在函数内部使用函数外部全局变量时,改变该变量的值,若直接赋值,则无论该赋值语句在函数什么位置,都将认为这个变量是函数的局部变量而不再向外找了。正确的方式是使用global关键字在函数内部声明一下。

旅行者实例

a.闭包方法:
在函数内使用nonlocal声明变量,可以使该变量不是代表局部变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
start = 0
def loc(pos):
def go(step):
nonlocal pos
new_pos = pos + step
pos = new_pos
print('now the position is : '+str(new_pos))
return go

trip = loc(start)
trip(2)#now the position is : 2
print(trip.__closure__[0].cell_contents) # 2
trip(8)
print(trip.__closure__[0].cell_contents) # 10

b. 不用闭包的方法:
(不推荐大量使用global关键字,破坏函数封装性)

分享到