zoukankan      html  css  js  c++  java
  • 十一、python的高级语法与用法

    一、枚举其实是一个类

    现实世界中的“类型”,在计算机世界中如何描述?

    常见的

    1)用1、2、3..等数字表示类型

    2)较好的做法是用字典表示

    3)最好的是使用枚举

     1 # coding=utf-8
     2 from enum import Enum
     3 
     4 
     5 class VIP(Enum):  # 继承Enum类
     6     YELLOW = 1  # 枚举类型建议使用大小
     7     GREEN = 2
     8     BLACK = 3
     9     RED = 4
    10 
    11 print(VIP.YELLOW)

    1、python中,枚举的本质是类

    2、使用时需要继承Enum类

    3、类中定义一组常量,建议使用全大写字母表示

    4、数字1、2、3其实没有意义,枚举的意义重在标识,不在取值。

    二、枚举与普通类相比的优势

    如果不使用枚举,如何表示类型

    1)使用模块中的全局变量

    yellow=1

    green=2

    2) 字典

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

    3) 普通类

    class TypeDiamond():

      yellow=1

      green=2

    缺点:

    1)可变,即可以在代码中轻易改变

    2)没有防止相同标签的功能

    现实中的‘类型’一旦定义不应该被轻易更改,但字典可以通过赋值改变类型,同样普通类也可以轻易改变类型。

    字典和普通类允许变量(类型)相同

    {‘yellow’:1,'yellow:2}

    在python中没有真正的常量,在枚举中定义的类型不能被更改,且不能取相同的标记。

    1)枚举的保护性

    2)枚举的防重性

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

    1、获取某个枚举标签的值.value

    2、获取某个枚举标签的名字.name

    3、通过枚举标签的名称获取枚举的类型

    4、枚举可遍历

    1 # 获取枚举标签的值
    2 print(VIP.YELLOW.value)
    3 # 获取枚举标签的名字
    4 print(VIP.YELLOW.name)
    5 # 获取枚举类型
    6 print(VIP.YELLOW)
    7 for v in VIP:
    8     print(v)

    1                           枚举值
    YELLOW              枚举名称
    VIP.YELLOW   枚举类型

    四、枚举之间的比较

    枚举支持的比较

    1)等值比较

    res=VIP.YELLOW==VIP.GREEN
    print(res)


    打印结果:False

    2)身份比较

    res=VIP.YELLOW is VIP.YELLOW
    print(res)
    打印结果:True

    枚举不支持的比较

    1)名称和值的比较

    class VIP(Enum):
    YELLOW = 1 # 枚举类型建议使用大小
    GREEN = 2
    BLACK = 3
    RED = 4

    res=VIP.YELLOW ==1
    print(res)
    打印结果:False

    2)大小比较

    res=VIP.YELLOW <VIP.GREEN
    print(res)

    报错:TypeError: '<' not supported between instances of 'VIP' and 'VIP'

    3)枚举类之间的比较

    class VIP(Enum):
    YELLOW = 1 # 枚举类型建议使用大小
    GREEN = 2
    BLACK = 3
    RED = 4

    class VIP1(Enum):
    YELLOW = 1 # 枚举类型建议使用大小
    GREEN = 2
    BLACK = 3
    RED = 4

    res=VIP.YELLOW ==VIP1.YELLOW
    print(res)
    打印结果:False

    五、枚举注意事项
    1、不能使用相同的标签
    2、取值可以相同,但会作为别名,不能作为独立的枚举类型
    3、枚举的遍历,取值相等时,不打印(无法访问)别名
     1 # coding=utf-8
     2 from enum import Enum
     3 
     4 
     5 class VIP(Enum):
     6     YELLOW = 1  # 枚举类型建议使用大小
     7     YELLOW2 = 1
     8     BLACK = 3
     9     RED = 4
    10 
    11 for v in VIP:
    12     print(v)

    4、如何遍历(访问)别名?VIP.__members__
     
     1 # coding=utf-8
     2 from enum import Enum
     3 
     4 
     5 class VIP(Enum):
     6     YELLOW = 1  # 枚举类型建议使用大小
     7     YELLOW2 = 1
     8     BLACK = 3
     9     RED = 4
    10 
    11 for v in VIP.__members__:
    12     print(v)
    
    

    六、枚举的转换

    1、将枚举类型转化为数字

    实际编码过程中,推荐:在代码中定义枚举类型,数据库中存储枚举值,通过枚举名称访问数据库中的枚举值

    if a==VIP.YELLOW:#不推荐使用a==1

      print(...)

    if a==VIP.GREEN:#不推荐使用a==2

      print(...)

    2、将数字转化为枚举类型

    a=1

    print(VIP(a))

     1 # coding=utf-8
     2 from enum import Enum
     3 
     4 
     5 class VIP(Enum):
     6     YELLOW = 1  # 枚举类型建议使用大小
     7     YELLOW2 = 1
     8     BLACK = 3
     9     RED = 4
    10 
    11 a=1
    12 print(VIP(a))

    七、枚举小结

    1、IntEunm类

    枚举值可以是int类型,也可以是str类型,如果明确了是int类型,可以使用IntEunm类,该类限制了枚举值只能是int

    1 #coding=utf-8
    2 from enum import IntEnum
    3 
    4 
    5 class VIP(IntEnum):
    6     YELLOW = 'a' # 枚举类型建议使用大小
    7     YELLOW2 = 1
    8     BLACK = 3
    9     RED = 4

    2、限制别名(不能取相同值)

    1 #coding=utf-8
    2 from enum import IntEnum,unique
    3 
    4 @unique
    5 class VIP(IntEnum):
    6     YELLOW = 1 # 枚举类型建议使用大小
    7     YELLOW2 = 1
    8     BLACK = 3
    9     RED = 4

    3、枚举在python中是单例模式,不能实例化

    这里引入了设计模式的概念,其中单例模式是23种设计模式中的一种。

    八、函数式编程、闭包导论

    1、python支持函数式编程,该用的时候用

    2、概念不重要,重要的是思维

    3、函数:其他语言中函数是指一段可执行的代码,并不是对象,但在python中,函数就是对象,可实例化

    #coding=utf-8

    def a():
    pass

    print(type(a))

    
    

    python:一切皆对象

    那么

    • 函数可以赋值给变量
    • 函数可作为另一个函数的参数
    • 函数可作为另一个函数的返回结果

    九、什么是闭包

    闭包=函数+环境变量

    环境变量:函数定义时用到的变量(在函数外)

     1 # coding=utf-8
     2 
     3 def curve_pre():  # 闭包
     4     a = 25  # 环境变量
     5 
     6     def curve(x):  # 函数
     7         return a * x * x  #引用环境变量a
     8 
     9     return curve  # 返回函数
    10 
    11 
    12 f = curve_pre()
    13 print(f(2))

    结果:100

    对a重新赋值,结果如何?

     1 # coding=utf-8
     2 
     3 def curve_pre():  # 闭包
     4     a = 25  # 环境变量
     5 
     6     def curve(x):  # 函数
     7         return a * x * x  #引用环境变量a
     8 
     9     return curve  # 返回函数
    10 
    11 a=10
    12 f=curve_pre()
    13 print(f(2))

    结果仍然是:100

    如何获取环境变量的值25

     1 # coding=utf-8
     2 
     3 def curve_pre():  # 闭包
     4     a = 25  # 环境变量
     5 
     6     def curve(x):  # 函数
     7         return a * x * x  #引用环境变量a
     8 
     9     return curve  # 返回函数
    10 
    11 f = curve_pre()
    12 #获取环境变量的值
    13 print(f.__closure__[0].cell_contents)

    十、一个事例看闭包

    闭包的意义:保存环境,现场

    局部变量不影响外部的环境变量

     1 # coding=utf-8
     2 
     3 def f1():
     4     a = 10
     5 
     6     def f2():
     7         a = 20
     8         print(a)
     9 
    10     print(a)
    11     f2()
    12     print(a)
    13 
    14 f1()

    打印结果:

    10
    20
    10

    十一、闭包的经典误区

    代码1

    1 #coding=utf-8
    2 
    3 def f1():
    4     a=10
    5     def f2():
    6         a=20 #a出现在表达式的作为,会被当做局部变量
    7 
    8 f=f1()
    9 print(f.__closure__)

    打印结果:

    Traceback (most recent call last):
      File "E:/pyClass/eleven/c11.py", line 9, in <module>
        print(f.__closure__)
    AttributeError: 'NoneType' object has no attribute '__closure__'

    原因:

    f1()不是闭包,因为没有返回?

    代码2:加入返回

     1 # coding=utf-8
     2 
     3 def f1():
     4     a = 10
     5 
     6     def f2():
     7         a = 20  # a出现在表达式的作为,会被当做局部变量
     8 
     9     return f2
    10 
    11 
    12 f = f1()
    13 print(f.__closure__)

    打印结果:None

    原因:函数f2没有返回?

    代码3:在f2中增加返回

     1 # coding=utf-8
     2 
     3 def f1():
     4     a = 10
     5 
     6     def f2():
     7         a = 20  # a出现在表达式的作为,会被当做局部变量
     8         return a
     9     return f2
    10 
    11 
    12 f = f1()
    13 print(f.__closure__)

    打印结果:None

    原因:f2中没有引用环境变量

    代码4

     1 # coding=utf-8
     2 
     3 def f1():
     4     a = 10
     5 
     6     def f2():
     7         # a = 20  # a出现在表达式的作为,会被当做局部变量
     8         return a
     9     return f2
    10 
    11 
    12 f = f1()
    13 print(f.__closure__)

    打印结果:(<cell at 0x00000000006CA5E8: int object at 0x000000001DCEB560>,)

    总结

    1)环境变量不能作为局部变量被赋值

    2)需要返回函数

    3)函数需要引用环境变量

    十二、几个问题,用闭包解决

    问题:计算旅行者当前位置,假设起点x=0,每走一步,x+1

    问题关键:保存上次结果

    起点:x=0

    每走一步:x+1

    3步:result=3

    5步:result=8

    6步:result=14

    方法一:非闭包

     1 #coding=utf-8
     2 
     3 origin=0
     4 
     5 def go(step):
     6     new_pos=origin+step
     7     origin=new_pos
     8     return origin
     9 
    10 print(go(2))
    11 print(go(3))
    12 print(go(5))

    报错信息:

    Traceback (most recent call last):
      File "E:/pyClass/eleven/c12.py", line 10, in <module>
        print(go(2))
      File "E:/pyClass/eleven/c12.py", line 6, in go
        new_pos=origin+step
    UnboundLocalError: local variable 'origin' referenced before assignment

    原因:第7行中,origin出现在表达式左边,会被认为是局部变量,局部变量在6行中没有定义就使用,系统认为是错误的

    尝试解决:

    注释掉第7行,不再报错,但是打印结果

    0

    0

    0

    与预期不符

    最终解决:使用global关键字,声明origin为全局变量

     1 #coding=utf-8
     2 
     3 origin=0
     4 def go(step):
     5     global origin
     6     new_pos=origin+step
     7     origin=new_pos
     8     return origin
     9 
    10 print(go(2))
    11 print(go(3))
    12 print(go(5))

    打印结果

    2
    5
    10
    方法二:使用闭包

     1 # coding=utf-8
     2 
     3 origin = 0
     4 
     5 
     6 def factory(pos):
     7     def go(step):
     8         nonlocal pos  # 声明pos非局部变量
     9         new_pos = pos + step
    10         pos = new_pos
    11         return pos
    12 
    13     return go
    14 
    15 
    16 tourist = factory(origin)
    17 print("旅行者当前位置:%s" % (tourist(2)))
    18 print("origin变量的值:%s" % (origin))
    19 print("环境变量的值:%s" % (tourist.__closure__[0].cell_contents))
    20 print("旅行者当前位置:%s" % (tourist(3)))
    21 print("origin变量的值:%s" % (origin))
    22 print("环境变量的值:%s" % (tourist.__closure__[0].cell_contents))
    23 print("旅行者当前位置:%s" % (tourist(5)))
    24 print("origin变量的值:%s" % (origin))
    25 print("环境变量的值:%s" % (tourist.__closure__[0].cell_contents))

    打印结果:

    旅行者当前位置:2
    origin变量的值:0
    环境变量的值:2
    旅行者当前位置:5
    origin变量的值:0
    环境变量的值:5
    旅行者当前位置:10
    origin变量的值:0
    环境变量的值:10
    总结

    1)origin并没有被改变

    2)pos环境变量被记住

    
    
  • 相关阅读:
    Redis持久化
    Redis进阶——事务、TTL、排序、消息通知、管道
    行为设计模式
    Redis数据类型
    ASP.NET并发处理
    c# 泛型有什么作用?
    IBatisNet 升级到 .Net Framework 4.0 时发现 IBatisNet 一小BUG
    【Python3】用for循环和while循环分别打印出如下格式“九九乘法表”
    Visual Studio 2010 SP1 WPF程序属性重命名BUG,小心!
    为什么用SOA架构?
  • 原文地址:https://www.cnblogs.com/loveapple/p/9354231.html
Copyright © 2011-2022 走看看