美文网首页Python
10、枚举与闭包

10、枚举与闭包

作者: IT_Freak | 来源:发表于2018-12-24 19:27 被阅读0次

    枚举

    枚举类:
    from enum import Enum  #导入枚举类
    
    class VIP(Enum):
        YELLOW = 1
        GREEN = 2
        BLACK = 3
        RED = 4
     
    print(VIP.YELLOW)
    
    结果:VIP.YELLOW    #关注的是它的标签而不是数字
    
    枚举和普通类相比有什么优势
    三种其他的普通方法表示枚举:
    1)
    yellow = 1
    green = 2
    2)
    {'yellow':1,'green':2}    
    3)
    class TypeDiamond():
        yellow = 1
        green = 2
    
    特点:他们都是可变的,可以在代码中轻易的更改值,且没有防止相同标签的功能。
    
    枚举的特点:
    from enum import Enum
    
    class VIP(Enum):
        YELLOW = 1
        YELLOW= 2   #不可重复,否则报错
        BLACK = 3
        RED = 4
    
    VIP.YELLOW = 6    #枚举类内的数据不可更改,否则会报错
    
    枚举类型、枚举名称与枚举值
    获取枚举变量的数值:
    from enum import Enum
    
    class VIP(Enum):
        YELLOW = 1
        GREEN = 2
        BLACK = 3
        RED = 4
       
    print(VIP.YELLOW.value)  #获取变量的数值
    结果:1
    
    print(VIP.YELLOW.name)  #获取变量的名称
    结果:YELLOW   #str类型
    
    print(VIP.YELLOW)   #获取枚举变量 
    print(VIP['YELLOW'])
    结果:VIP.YELLOW  #<enum 'VIP'>
    
    print(type(VIP.YELLOW))  #获取获取变量类型
    结果:<enum 'VIP'>
    
    
    枚举是可以遍历的:
    for v in VIP :
        print(v)
    结果:
    VIP.YELLOW
    VIP.GREEN
    VIP.BLACK
    VIP.RED
    

    枚举的比较运算

    • 两个枚举之间可以使用等值比较(==),但不能进行大小比较。
    • 支持身份验证(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
    

    枚举注意事项

    枚举的数值可以相同,在这种情况下,将第二种枚举类型看成别名。遍历时不会打印别名:
    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: 1>)
    ('BLACK', <VIP.BLACK: 3>)
    ('RED', <VIP.RED: 4>)
    
    
    遍历__members__:
    for v in VIP.__members__:   #获取枚举类的成员
        print(v)
    结果:
    YELLOW
    GREEN
    BLACK
    RED
    

    枚举转换

    在数据库里一般存储数值或者标签名字来代表枚举类型,推荐存储数值.数字占用的空间更小。但是不建议在代码中用数值代表枚举,可读性不强。

    如何将数字转换成枚举类型:
    from enum import Enum
    
    a = 1
    class VIP(Enum):
        YELLOW = 1
        GREEN = 2
        BLACK = 3
        RED = 4
    
    print(VIP(a))    #转换枚举类型
    
    结果:VIP.YELLOW
    

    数字枚举

    要求每个枚举类型都是数字的时候继承IntEnum:
    from enum import IntEnum
    
    class VIP(IntEnum):
        YELLOW = 1
        GREEN = 2
        BLACK = 3
        RED = 4
    
    限制不同的枚举类型不能取相同的值:
    from enum import IntEnum,unique
    
    @unique    #装饰器
    class VIP(IntEnum):
        YELLOW = 1
        GREEN = 2
        BLACK = 3
        RED = 4
    
    枚举类型不能实例化,属于单例模式
    

    进阶内容

    业务逻辑的开发者,不要考虑太多的封装性
    包和类库的开发者,要考虑封装性

    一切皆对象

    python中的函数是对象,一切皆对象。可以把函数赋值给变量:

    a = 1
    a = '2'
    a = def
    

    甚至可以把函数当作另外一个函数的参数传递或者当成返回值返回。

    闭包

    内部函数
    def curve_pre():
        def curve():
            pass
    
    curve()    #报错,因为curve()的作用域仅限于curve_pre()的内部
    
    
    闭包
    def curve_pre():
        a = 25 
        def curve(x): 
            return a * x * x  #局部变量找不到会到上一级找
        return curve #返回一个函数
    
    f = curve_pre()
    print(f(2)) #调用curve()函数
    结果:100
    
    外部变量不会影响到闭包
    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的值被改变了
    
    查看闭包:
    f = curve_pre()
    print(f.__closure__)  #闭包函数,如果不是闭包会报错
    print(f.__closure__[0].cell_contents)
    
    结果:
    (<cell at 0x0031AAF0: int object at 0x0FF93A80>,)  #闭包的存储地址
    25    #获取环境变量 a
    

    闭包理解

    个人理解:闭包就是一个封闭的环境,这里我们使用函数实现,当外部调用函数。外侧函数(变量+内函数),需要返回内函数。此时才可以调用这个闭包。
    闭包函数和普通函数最大的区别就是返回值不是数值。

    内函数,没有使用环境变量,会出错。
    def f1():
        a = 10
        def f2():
            a = 20    #a被认为是一个局部变量了,就不认为是个环境变量了
            return a
        return f2
     
    f = f1()
    print(f.__closure__)    #没有__closure__属性
    结果:None
    
    正确的闭包示范:
    def f1():
        a = 10
        def f2():
            return a
        return f2
    
    f = f1()
    print(f.__closure__)
    结果:(<cell at 0x02F5AAF0: int object at 0x0FF93990>,)
    

    环境变量不能当作一个变量去赋值,而是一定要去引用外函数的变量(这里与我们定义类时,十分相似)。

    旅行者问题

    x = 0 为起点,每次计算出旅行者当前所处的位置。

    使用全局变量实现:
    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
    
    使用闭包实现:
    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的值
    

    相关文章

      网友评论

        本文标题:10、枚举与闭包

        本文链接:https://www.haomeiwen.com/subject/fwczkqtx.html