11-1 枚举其实是一个类

枚举类:
from enum import Enum
 
class VIP(Enum):
    YELLOW = 1
    GREEN = 2
    BLACK = 3
    RED = 4
 
print(VIP.YELLOW)
#VIP.YELLOW    #关注的是它的标签不是数字
可以用VIP.BLACK等来进行表示。
 
11-2 枚举和普通类相比有什么优势
 
三种其他的普通方法表示枚举:
yellow = 1
green = 2
 
{'yellow':1,'green':2}    
 
class TypeDiamond():
    yellow = 1
    green = 2
他们都是可变的,可以在代码中轻易的更改值,且没有防止相同标签的功能。
 
枚举的特点:
from enum import Enum
 
class VIP(Enum):
    YELLOW = 1
    YELLOW= 2   #不可重复,报错
    BLACK = 3
    RED = 4
 
print(VIP.YELLOW)
VIP.YELLOW = 6    #不可更改,报错
 
11-3 枚举类型、枚举名称与枚举值
 
获取枚举类型下某一数值:
from enum import Enum
 
class VIP(Enum):
    YELLOW = 1
    GREEN = 2
    BLACK = 3
    RED = 4
    
print(VIP.YELLOW.value)
print(VIP.YELLOW.name)
print(VIP.YELLOW)
print(VIP['GREEN'])
#1
#YELLOW    #str
#VIP.YELLOW    #enum 'VIP'    枚举类型
#VIP.YELLOW    #enum 'VIP'    枚举类型
 
枚举是可以遍历的:
for v in VIP :
    print(v)
 
11-4 枚举的比较运算 
 
两个枚举之间可以使用等值比较(==),与数值比较的判断结果不对。两个枚举之间不能进行大小比较。
支持is操作:
result = VIP.BLACK is VIP.GREEN
 
两个大类之间也可以进行等值比较,不过结果是False:
from enum import Enum
 
class VIP(Enum):
    YELLOW = 1
    GREEN = 2
    BLACK = 3
    RED = 4
    
class VIP1(Enum):
    YELLOW = 1
    GREEN = 2
    BLACK = 3
    RED = 4
 
print(VIP.GREEN ==VIP1.GREEN)
#False
 
11-5 枚举注意事项
 
枚举的数值可以相同,在这种情况下,将第二种枚举类型看成别名。遍历时不会打印别名:
class VIP(Enum):
    YELLOW = 1
    GREEN = 1    #别名,不会报错
    BLACK = 3
    RED = 4
 
把别名加入遍历循环:
for v in VIP.__members__.items() :
    print(v)
#('YELLOW', <VIP.YELLOW: 1>)
#('GREEN', <VIP.GREEN: 2>)
#('BLACK', <VIP.BLACK: 3>)
#('RED', <VIP.RED: 4>)
或者遍历__members__:
for v in VIP.__members__:
    print(v)
#YELLOW
#GREEN
#BLACK
#RED
 
11-6 枚举转换
 
在数据库里一般存储数值或者标签名字来代表枚举类型,推荐存储数值,数字占用的空间更小。但是不建议在代码种用数值代表枚举,可读性不强。
 
如何将数字转换成枚举类型:
from enum import Enum
 
a = 1
class VIP(Enum):
    YELLOW = 1
    GREEN = 2
    BLACK = 3
    RED = 4
 
print(VIP(a))    #转换枚举类型
#VIP.YELLOW
 
11-7 枚举小结
 
要求每个枚举类型都是数字的时候继承IntEnum:
from enum import IntEnum
 
class VIP(IntEnum):
    YELLOW = 1
    GREEN = 2
    BLACK = 3
    RED = 4
 
限制不同的枚举类型不能取相同的值:
from enum import Enum
from enum import IntEnum,unique
 
@unique    #装饰器
class VIP(IntEnum):
    YELLOW = 1
    GREEN = 2
    BLACK = 3
    RED = 4
 
枚举类型不能实例化,属于单例模式
 
11-8 进阶内容开场白
 
业务逻辑的开发者,不考虑太多的封装性
包和类库的开发者,要考虑封装性
 
11-9 一切皆对象
 
函数式编程并没有标准定义,如果代码非常繁琐则考虑使用。
 
学习闭包的概念,不是python独有的。
其他大多数语言中的函数只是一段可执行的代码,并不是对象。
python中的函数是对象,一切皆对象。可以把函数赋值给变量:
a = 1
a = '2'
a = def
甚至可以把函数当作另外一个函数的参数传递或者当成返回值返回,而C#中要封装成委托。
 
11-10 什么是闭包
 
例1:
def curve_pre():
    def curve():
        pass
 
curve()    #找不到,因为curve()的作用域仅限于curve_pre()的内部
例2:
def curve_pre():
    def curve():
        pass
    return curve    #函数可以作为结果返回
 
f = curve_pre()    #函数可以赋值
f()
例3:
def curve_pre():
    a = 25 #局部变量在curve的外部
    def curve(x): #接受抛物线的x值
        return a * x * x
    return curve #返回一个函数
 
f = curve_pre()
print(f(2)) #调用curve()函数
#100
简化:
a = 10
def f1(x):
    return a * x * x
 
print(f1(2))
#40         #局部变量找不到会去上一级找
例4与例3对比:
def curve_pre():
    a = 25 #局部变量在curve的外部
    def curve(x): #接受抛物线的x值
        return a * x * x
    return curve #返回一个函数
 
a = 10     #定义a = 10
f = curve_pre()
print(f(2)) #调用curve()函数
#100        #仍然是a = 25的取值,取得是定义时的环境变量,这就是闭包
函数及其外部环境变量所构成的整体叫做闭包
环境变量要在函数外部,但不能是全局变量:
a = 25    #a定义为了全局变量
def curve_pre():
    def curve(x): #接受抛物线的x值
        return a * x * x
    return curve #返回一个函数
 
a = 10
f = curve_pre()
print(f(2)) #调用curve()函数
#40    #a的值被改变了
查看:
def curve_pre():
    a = 25 #局部变量在curve的外部
    def curve(x): #接受抛物线的x值
        return a * x * x
    return curve #返回一个函数
 
a = 10
f = curve_pre()
print(f.__closure__)
print(f.__closure__[0].cell_contents)
print(f(2)) #调用curve()函数
#(<cell at 0x0031AAF0: int object at 0x0FF93A80>,)
#25    #这里是a的值
#100
 
11-11 一个事例看看闭包 
 
闭包保存的是一个环境,把函数现场保存起来了。
闭包 = 函数 + 函数定义时的环境变量
def f1():
    a = 10
    def f2():
        a = 20    #对a重新赋值
        print(a)
    print(a)    
    f2()    #调用
    print(a)
 
11-12 闭包的经典误区
 
def f1():
    a = 10
    def f2():
        a = 20    #对a重新赋值局部变量,不会影响到外部
        print(a)
    print(a)    #10
    f2()    #20
    print(a)    #10
 
f1()
#10
#20
#10
从外层向内层分析
 
查看其是不是一个闭包:
def f1():
    a = 10
    def f2():
        a = 20
        # print(a)
    #print(a)
    f2()
    #print(a)
 
f = f1()    #f1是None类型
print(f.__closure__)    #报错
加上返回值,仍然不是闭包函数:
def f1():
    a = 10
    def f2():
        a = 20    #a被认为是一个局部变量了,就不认为是个环境变量了
        return a
    return f2
 
f = f1()
print(f.__closure__)    #没有__closure__属性
#None
去掉f2()中的赋值后是闭包函数:
def f1():
    a = 10
    def f2():
        #a = 20    #删除a = 20
        return a
    return f2
 
f = f1()
print(f.__closure__)
#(<cell at 0x02F5AAF0: int object at 0x0FF93990>,)
环境变量不能当作一个变量去赋值,而是一定要去引用外部。
 
11-13 出个题,用闭包解决!
 
闭包不是必不可少的东西,只是可以使你的代码架构更加合理。
 
旅行者,x = 0 为起点,计算出旅行者当前所处的位置。
关键点:每次调用时需要调用上次的状态
 
11-14 我先用非闭包解决一下
 
origin = 0
 
def go(step):
    global origin    #将origin变成全局变量
    new_pos = origin + step
    origin = new_pos
    return origin
 
print(go(2))
print(go(3))
print(go(6))
#2
#5
#11
 
11-15 再用闭包解决一下
 
origin = 0
def factory(pos):    #工厂模式
    def go(step):
        nonlocal pos #强制声明不是局部变量
        new_pos = pos + step
        pos = new_pos
        return new_pos
    return go
    
tourist = factory(origin)
print(tourist(2))
print(tourist(3))
print(tourist(6))
#2
#5
#11

并没有改变全局变量origin的值

 

11-16 小谈函数式编程

 

python和Javascript都会使用闭包。

在一个函数外部间接调用函数内部的变量,从模块级别调用局部变量。

极易造成内存泄漏。