Python3 笔记 11 Python的高级语法与用法

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都会使用闭包。

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

极易造成内存泄漏。

我的个人博客:http://www.unconstraint.cn

猜你喜欢

转载自blog.csdn.net/qq_36329973/article/details/81155127