10.python的高级语法与用法、闭包

枚举其实是一个类

from enum import Enum

class VIP(Enum):
    YELLOW = 1
    GREEN = 2
    BLACK = 3
    RED = 4

print(VIP.YELLOW)  # -> VIP.YELLOW

枚举的意义是其名字 而不是其数值

枚举类和普通类相比有什么优势

表示一连串类型的方法:
1.普通的类和字典第一个缺陷是,没有防止改变的机制。
2.没有防止相同标签的功能

枚举类型、枚举名称与枚举值:

通过type函数查看

print(type(VIP.GREEN.name))  # 枚举的名字
print(type(VIP.GREEN))  # 枚举的类
print(type(VIP["GREEN"])) # 枚举的类

枚举类可以遍历
廖雪峰--枚举类

枚举的比较运算

result = VIP.GREEN
assert result != VIP.BLACK, "false"
assert result is VIP.GREEN, "false"

枚举可以进行相等与不等比较,不能进行大小比较。
可以 is 比较。身份比较
对于不同的枚举类,即使名字和值一样,也不相等。属于不同类

枚举注意事项

1.枚举下不能有相同的标签
2.枚举下可以有相同的值,那么第一个类型之后的相同值的名字是第一个类型的别名!!!枚举类有装饰器@unique检查保证不重复(相同值)

from enum import Enum # unique

# @unique
class VIP(Enum):
    YELLOW = 1
    GREEN = 2
    BLACK = 2
    RED = 4

print(VIP.YELLOW)
print(type(VIP.GREEN.name))
print(type(VIP.GREEN))
print(type(VIP["GREEN"]))

result = VIP.GREEN
assert result == VIP.BLACK, "false"  # 由于重复的赋值,导致两个成员值相等,并且调用BLACK返回的名字会是GREEN
assert result is VIP.GREEN, "false"

for v in VIP:  # 没有BLACK
    print(v)

for v in VIP.__members__:  # 有BLACK
    print(v)

很有意思,感觉有一定的实用价值。

枚举转换

推荐存储类型的方法:存储数字,采用枚举类来解析所存储的数字。能增加代码的可读性。
通过数字读取枚举类的方法 -> print(VIP(1))

枚举小结:

Enum值可以是字符串,如果需要强制是整数,需要用到IntEnum
枚举类用装饰器@unique检查保证不重复(相同值?)
采用的是单例模式,所以无法实例化 -> 猜到了
23种设计模式

进阶内容开场白

高阶知识用在编程哪些方面:
包、类库的开发者。

一切皆对象

函数式编程
如果用类写代码写的很繁琐,别扭,就可以考虑函数式编程
闭包的概念
廖雪峰--闭包--封装
可以把一个函数作为另一个函数的参数传递进去
也可以把一个函数作为另一个函数的返回结果。
个人认识:主要看一个函数的运行结果是关于函数的引用还是关于函数的调用。

什么是闭包

个人认识:就是初次运行函数并不返回运行值,而是返回一个可调用的对象,在此调用就会返回运行值。

# 最简单的闭包
# 返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量。
def curve_pre():
    a = 25
    
    def curve(x):
        y = a * x ^ 2 + x
        return y
    return curve


re = curve_pre()
print(re)  # .curve at 0x7f73b9e27158>
print(re.__closure__)  # 闭包的参数对象
print(re.__closure__[0].cell_contents)  # 返回闭包的参数
print(re(2))

闭包需要调用到函数的局部变量,否则闭包意义不大。
返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量。

一个事例看闭包

闭包 = 函数 + 环境的变量(局部变量)
闭包的意义:保存的是一个环境 -> 不可调用后续发生变化的值。(最好是调用局部变量)
需要注意的地方:

def f1():
    a = 10
    def f2():
        a = 20
        print(a)
    print(a)
    f2()
    print(a)

f1() # 返回 10  20  10

闭包的经典误区

def f1():
    a = 10
    def f2():
        a = 20  # 闭包内部不能定义局部变量 可以采用 a = a + 10 的方式引用外部变量
        return a
    return f2

f = f1()
print(f)
print(f.__closure__)  # 返回None,一旦函数的内部定义赋值了局部变量,将不再形成闭包,必须引用外部变量!!!

出个题,用闭包解决

我先用非闭包解决一下

origin = 0

def go(step):
    global origin
    new_pos = origin + step
    origin = new_pos
    return origin

print(go(2))
print(go(3))
print(go(6))

再用闭包解决一下

origin = 0

def factory(pos):

    def move(step):
        nonlocal pos
        new_pos = pos + step
        pos = new_pos
        return new_pos

    return move

f = factory(origin)

print(f(2))
print(f(3))
print(f(8))

自封闭性,没有取改变全局变量的值。而是自己保存上次执行完成之后的环境的变量,将变量的改变局限在函数内部。
闭包
如果用类,类变量就能解决此问题。

小谈函数式编程

factory : 工厂模式
python的闭包强调的是保存环境变量
javascript的闭包强调的是函数外部访问函数内部的变量
由于闭包产生的函数以及变量是常驻内存,容易导致内存泄漏。

你可能感兴趣的:(10.python的高级语法与用法、闭包)