Python之高级语法与用法(八)

一.枚举其实是一个类

建议标识名字用大写

1.枚举类:

from enum import Enum


class VIP(Enum):

    YELLOW = 1

    GREEN = 2

    BLACK = 3

    RED = 4


print(VIP.YELLOW)

#VIP.YELLOW    #关注的是它的标签不是数字

2 枚举和普通类相比的优势

三种其他的普通方法表示枚举:

(1)

yellow = 1

green = 2

(2)字典的表示方式

{'yellow':1,'green':2}    

(3)类的表示方式

class TypeDiamond():

    yellow = 1

    green = 2

 

这些方式,它们都是可变的,可以在代码中轻易的更改值,且没有防止相同标签的功能。

3.枚举的特点:

from enum import Enum


class VIP(Enum):

    YELLOW = 1

   #YELLOW= 2   #不可重复,报错

    BLACK = 3

    RED = 4



print(VIP.YELLOW)

#VIP.YELLOW = 6    #不可更改,报错

 

二.枚举类型、枚举名称与枚举值

 

1.获取枚举类型下某一数值:

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['YELLOW'])

#1        #枚举值

#YELLOW    #<class 'str'> 获取标签名

#VIP.YELLOW    #<enum 'VIP'>    枚举类型

#VIP.YELLOW    

2.枚举是可以遍历的:

from enum import Enum


class VIP(Enum):

    YELLOW = 1

    GREEN = 2

    BLACK = 3

    RED = 4

for v in VIP :

    print(v)

#VIP.YELLOW
VIP.GREEN
VIP.BLACK
VIP.RED

 

三. 枚举的比较运算 

1.两个枚举之间可以使用等值比较(==),枚举与数值比较的判断结果不对。两个枚举之间不能进行大小比较。

2.支持is操作:

result = VIP.GREEN is VIP.GREEN

#True

3.两个大类之间也可以进行等值比较,不过结果是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

四.枚举注意事项

1.枚举的数值可以相同,在这种情况下,将第二种枚举类型看成别名。遍历时不会打印别名:

class VIP(Enum):

    YELLOW = 1

    GREEN = 1    #别名,不会报错

    BLACK = 3

    RED = 4

print(VIP.GREEN)

#VIP.YELLOW

 

2.把别名加入遍历循环:

(1)
for v in VIP.__members__.items() :

    print(v)

#('YELLOW', <VIP.YELLOW: 1>)

#('GREEN', <VIP.GREEN: 1>)

#('BLACK', <VIP.BLACK: 3>)

#('RED', <VIP.RED: 4>)

(2)

或者遍历__members__:

for v in VIP.__members__:

    print(v)

#YELLOW

#GREEN

#BLACK

#RED

五.枚举转换

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

2.如何将数字转换成枚举类型: 

from enum import Enum

a = 1

class VIP(Enum):

    YELLOW = 1

    GREEN = 2

    BLACK = 3

    RED = 4



print(VIP(a))    #转换枚举类型

#VIP.YELLOW

 

六.枚举小结

1.要求每个枚举类型都是数字的时候继承IntEnum:

from enum import IntEnum

class VIP(IntEnum):

    YELLOW = 1

    GREEN = 2

    BLACK = 3

    RED = 4

 

2.限制不同的枚举类型不能取相同的值:

from enum import Enum

from enum import IntEnum,unique


@unique    #装饰器

class VIP(IntEnum):

    YELLOW = 1

    GREEN = 2

    BLACK = 3

    RED = 4

枚举类型不能实例化,属于单例模式



一. 一切皆对象

 

函数式编程并没有标准定义,如果代码非常繁琐则考虑使用。

 

学习闭包的概念,不是python独有的。

其他大多数语言中的函数只是一段可执行的代码,并不是对象。

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

a = 1

a = '2'

a = def

甚至可以把函数当作另外一个函数的参数传递或者当成返回值返回,而C#中要封装成委托。

 

二.什么是闭包:闭包=函数+函数定义时的环境变量

1.

例1:

def curve_pre():

    def curve():

        pass



curve()    #找不到,因为curve()的作用域仅限于curve_pre()的内部

例2:

def curve_pre():

    def curve():
        print('This is a function')

        pass

    return curve    #函数可以作为结果返回



f = curve_pre()    #函数可以赋值

f()#执行函数,不会报错
#This is a function

例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

简化举例4:

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的取值,取得是定义时的环境变量,这就是闭包

函数及其外部环境变量所构成的整体叫做闭包

2.环境变量要在函数外部,但不能是全局变量:

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

三.一个事例看看闭包 

 

1.闭包的意义:闭包保存的是一个环境,把函数现场保存起来了。

                            闭包 = 函数 + 函数定义时的环境变量(不能是全局变量)

 

2. 闭包的经典误区

从外层向内层分析

def f1():

    a = 10

    def f2():

        a = 20    #对a重新赋值局部变量,不会影响到外部

        print(a)

    print(a)    #10

    f2()    #20 #f1内部调用f2

    print(a)    #10



f1()

#10

#20

#10

验证其是不是一个闭包:

(1)

def f1():

    a = 10

    def f2():

        a = 20

        # print(a)

    #print(a)

    f2()

    #print(a)



f = f1()    #f1是None类型

print(f.__closure__)    #报错

(2)加上返回值,仍然不是闭包函数:

def f1():

    a = 10

    def f2():

        a = 20    #a被认为是一个局部变量了,就不认为是个环境变量了

        return a

    return f2



f = f1()

print(f.__closure__)    #没有__closure__属性

#None

(3)去掉f2()中的赋值后是闭包函数:

def f1():

    a = 10

    def f2():

        #a = 20    #删除a = 20,此时a被python认为是一个局部变量

        return a

    return f2



f = f1()

print(f.__closure__)

#(<cell at 0x02F5AAF0: int object at 0x0FF93990>,)

原因:环境变量不能当作一个变量去赋值,而是一定要去引用外部。

 

四.出个题,用闭包解决!

:闭包不是必不可少的东西,只是可以使你的代码架构更加合理。

题目:

旅行者,x = 0 为起点,没走一步加1,计算出旅行者当前所处的位置。

关键点:每次调用时需要调用上次的结果

 

1.先用非闭包解决一下

origin = 0


def go(step):

    global origin    #将origin变成全局变量

    new_pos = origin + step

    origin = new_pos  #等号左边的origin被python认识是局部变量

    return origin



print(go(2))

print(go(3))

print(go(6))

#2

#5

#11

 

2.再用闭包解决一下

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(origin)

print(tourist(3))

print(tourist(6))

#2
#0

#5

#11

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

 

五.小谈函数式编程

  • python和Javascript都会使用闭包。
  • 闭包特点:在一个函数外部间接调用函数内部的变量,从模块级别间接调用局部变量。
  • 极易造成内存泄漏。
     
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值