十一、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环境变量被记住


原文地址:https://www.cnblogs.com/loveapple/p/9354231.html