Python3进阶(四)

一、Python高阶用法

  • 讲这一章节之前,我们先学习下Python的一个特性:python一切皆对象 ,举例如下
    1、变量可以赋值为函数、函数也是一个对象,类型是function;这在Java里面是不可能的
    2、一个函数里面可以返回另外一个函数

1.1、闭包

  • 闭包 = 函数 + 环境变量(函数外部的变量就是该函数的环境变量)
1、第一个简单的闭包程序
def current1():
    # a 叫做play的环境变量
    a = 25
    def play(x):
        return a * x *x
    
    return play

c1 = current1()
print('current1测试结果:' + str(c1(2)))
print('-----------------------------------------')
  • 测试结果:play函数可以使用它的外部环境变量a
    在这里插入图片描述

  • 思考:在闭包程序的外部将a的值改变会不会影响到play的输出结果?

    def current2():
        b = 30
        def play(x):
            return b * x * x
        
        return play
    
    b = 50
    c2 = current2()
    print('current2测试结果:' + str(c2(2)))
    
  • 测试结果:b = 50 并没有对play函数的运行结果产生影响
    在这里插入图片描述

  • 对比以上两段代码总结如下:
    1、b等于50并没有起到作用、play里面b的值只与play外面的b=30有关,b=30是play的环境变量; current2()与play形成了一个闭包
    2、b=50是外部变量,它的操作与play()无关、闭包 = 函数 + 环境变量(即play外层的current函数定义的变量)

2、闭包经典案例(笔试必考)
def test():
    a = 10
    def work():
        a = 50
        print(a)
    print(a)
    work()
    print(a)
test()
print("============================================================")
  • 执行结果:
    在这里插入图片描述

  • 上述程序执行流程分析:
    1、打印的是a = 10,不做过多解释
    2、执行work函数改变a的值,打印得到50
    3、a = 10

  • 从上我们可以得出以下结论:
    1、局部变量的操作不能够影响到外部环境变量
    2、此时work函数与test函数没有形成闭包了
    3、因为work函数与test函数没有形成闭包,所以现在work函数里面的a参数是作用于它本身的局部变量,并不是外部环境变量a,只有形成了闭包a = 10才是work函数的环境变量,这样在work函数里面就可以操作a = 50,这样外部环境变量a的值才会发生改变。

  • 加入下列新的闭包代码,对比分析:相较于第一个闭包程序,work函数多了一个 b = 20 的操作

  • python变量作用域:
    1、L (Local) 局部作用域
    2、E (Enclosing) 闭包函数外的函数中
    3、G (Global) 全局作用域
    4、B (Built-in) 内置作用域(内置函数所在模块的范围

    def test1():
        b = 10
        def work():
            b = 20
            return b * 2
        return work
    
    t1 = test1()
    print(t1)
    # 打印对象值:我们发现t1的对象并不存在即t1.__closure__的值为none,此时闭包效果没有了
    print(t1.__closure__)
    

    **__closure__字段是用来打印对象值的;**为none表示此次闭包失败

  • 测试结果:
    在这里插入图片描述

  • 执行流程分析:为什么闭包效果没有了,程序用b = 20这个局部变量计算,而不是用b = 10这个外部环境变量进行计算?
    1、此时work函数内的b变量会被python识别为work内新定义的环境变量即work函数本身的局部变量,与test1外部函数的b变量并没有关联关系, 此时闭包失效
    2、弥补方法:删除b = 20 即可实现闭包,print(t1.closure)也能打印出对象值,不会报none空
    3、如要实现闭包、b也就不能再work函数内进行新的复制操作,否则闭包失效

3、闭包经典面试问题:旅行者路程计数问题(必考)
  • 方式一:通过全局变量实现旅行者路程问题

    origin = 0
    
    def run(step):
        """  
        1、此时origin属于局部变量,run是拿不到外部全局变量origin,只有将run函数内部的局部变量origin声明为全局变量才能行的通
        2、global关键字就是将origin声明为全局变量的
        """
        global origin
        new_step = origin + step
        origin = new_step
        return new_step
    
    print(run(2))
    print(run(3))
    print(run(6))
    print('++++++++++++++++++++++++++++++')
    

    global 关键字是将局部变量声明为全局变量的,run是拿不到外部全局变量origin,只有将run函数内部的局部变量origin声明为全局变量才能行的通。

  • 测试结果:
    在这里插入图片描述

  • 思考:这种方式虽然能够实现需求,但是我们操作和修改的都是全局变量,通常情况下最好不要修改全局变量,这个时候我们就需要用到闭包了,推荐使用方式二

  • 方式二:闭包实现旅行者路程问题

    start = 0
    def factory(start):
        def run(step):
            """  
            1、此时start属于run的局部变量,和factory的外部变量没有关联,所以这个start相当于run函数中新建的局部变量
            2、解决方法:nonlocal关键字声明start不是run函数的局部变量,这样操作的就是外部的环境变量即factory函数的start变量
            """
            nonlocal start
            new_step = start + step
            start = new_step
            return start
        return run
    
    f = factory(start)
    # 我们可以观察到start全局变量并没有发生改变
    print(f(2))
    print('全局变量start值是否改变:'+ str(start))
    print(f(3))
    print('全局变量start值是否改变:'+ str(start))
    print(f(6))
    print('全局变量start值是否改变:'+ str(start))
    

    nonlocal 关键字的作用:
    1、当没有使用nonlocal 关键字时,start属于run的局部变量,和factory传入的外部环境变量start没有关联,所以这个start相当于run函数中新建的局部变量。
    2、解决方法:nonlocal关键字声明start不是run函数的局部变量,这样操作的就是外部的环境变量即factory函数的start变量

  • 运行结果:
    在这里插入图片描述

  • 总结:
    1、直接操作全局变量不可行,因为所有的函数都能操作全局变量,不安全
    2、闭包不会改变全局变量的值,推荐

1.2、Python高级表达式

1、lambda函数(匿名函数)
  • lambda函数,又名匿名函数,在其它的语言中叫做lambda表达式,如何使用:
    1、使用lambda关键字声明,且没有方法名
    2、冒号前面是方法要传递的参数、冒号后面是方法的返回值
    3、冒号后面只能是表达式,不能进行变量的赋值操作,不能是代码块
  • 使用lambda表达式实现两数相加之和:
    f = lambda x,y:x+y
    print('lambda函数运行结果:'+str(f(2,6)))
    print('+++++++++++++++++++++++++')
    
  • 测试结果:
    在这里插入图片描述
  • python的三元表达式:与Java的三元表达式有一点差异
    1、其它语言的表达方式:x > y ? x:y ,x 为表达式结果为true时返回,y为结果为false时返回
    2、python:表达式正确时的返回结果 if 表达式 else 表达式错误时的返回结果
    a = 2
    b = 1
    # 表达式条件成立,返回a
    print(a if a > b else b)
    
  • 测试结果:
    在这里插入图片描述
2、map函数
  • map、三元表达式常常和lambda表达式联合使用;map() 会根据提供的函数对指定序列做映射,
    第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表。

  • map 函数语法:

    map(function, iterable, ...)
    
  • 方式一:不使用map函数计算一个列表的每一个数字的平方

    list_x = [1,2,3,4,5,6]
    # 普通函数实现x的平方
    def  pingfang(x):
        return x * x
    
    for x in list_x:
        print(pingfang(x),end = ' | ')
    
    print('普通调用结束')
    print('====================================')
    
  • 测试结果:
    在这里插入图片描述

    • 方式二:使用map函数计算平方值
      m = map(pingfang,list_x)
      print(m)
      print(list(m))
      print('====================================')
      # 使用lambda函数与map函数精简执行
      ma = map(lambda x : x * x,list_x)
      print(ma)
      print(list(ma))
      print('====================================')
      
  • 测试结果:
    在这里插入图片描述

  • 由上可知map函数返回的是一个map类型的对象,所以我们需要将它转换成为我们所需要的数据类型。

  • 测试多个列表使用map

    list_a = [1,2,3,4,5,6,7,8]
    list_b = [1,2,3,4,5,6]
    
    m1 = map(lambda a,b:a+b,list_a,list_b)
    print(m1)
    print(list(m1))
    
  • 测试结果:
    在这里插入图片描述

  • 总结:
    1、lambda后面传递的list参数的个数要与lambda中要求传参的个数一致,一一对应
    2、当两个或多个集合长度不一样是,map的运行结果以序列长度较短的个数为准;如下以list_b 的元素个数为标准输出结果

3、reduce函数
  • 定义: 函数将一个数据集合(链表,元组等)中的所有数据进行下列操作:用传给 reduce 中的函数 function(有两个参数)先对集合中的第 1、2 个元素进行操作,得到的结果再与第三个数据用 function 函数运算,最后得到一个结果。
  • 什么是reduce:
    1、reduce主要做连续运算、连续调用lambda表达式或者函数
    2、使用方法:从functools模块导入reduce类即可使用
    3、reduce的lambda函数的参数必须是两个、一个或者两个以上都不行
    4、reduce只能操作一个序列,不能同时传入多个序列
    from functools import reduce
    
    list_x = [1,2,3,4,5,6,7,8]
    r1 = reduce(lambda x,y:x+y,list_x)
    print(r1)
    print('=======================================')
    
  • 测试结果:
    在这里插入图片描述
  • 执行流程分析:
    1、x = 1,y = 2 执行lambda函数得到结果为3
    2、上一次执行的结果为x,即x = 3,y = 3 执行lambda函数3 + 3 =6
    3、x = 6 ,y = 4 执行lambda函数结果为 6 + 4 = 10
    4、x = 10 ,y = 5 执行结果为10 + 5 = 15
    6、x = 15 ,y = 6 执行结果为15 + 6 = 21
    7、x = 21 ,y = 7 执行结果为21 + 7 = 28
    8、x = 28 ,y = 8 执行结果为28 + 8 = 36
  • reduce函数设置连续计算的起始值
    r2 = reduce(lambda x,y:x+y,list_x,10)
    print(r2)
    print('=======================================')
    
  • 测试结果:上述代码中10就是计算的初始值,没有指定默认为0
    在这里插入图片描述
4、filter过滤类
  • 作用:
    1、作用:将lambda表达式或者函数的返回结果为true的筛选并打印出来
    2、可以过滤一个序列,不能过滤多个序列
    3、返回一个filter的对象

    list_x = [1,2,3,4,5,6]
    f = filter(lambda x:True if x > 3 else False,list_x)
    print(f)
    print(list(f))
    
  • 测试结果:
    在这里插入图片描述

二、Python的装饰器

  • 定义:类似于Java里面的@标签,可复用,简化代码结构;装饰器对修改是封闭的,对扩展是开放的。

2.1 自定义装饰器:获取当前时间

  • 自定义装饰器

    import time
    # 自定义装饰器:获取当前时间
    def dirhappy(fun):
        def happy(name):
            # time.time()获取当前时间
            print(time.time())
            fun(name)
        return happy
    
  • 原生调用方式

    def test1(name):
        print('this id a directory test1' + str(name))
    # 原生调用方式
    h1 =  dirhappy(test1)
    h1('zhangsan')
    print('=================================')
    
  • 测试结果
    在这里插入图片描述

  • 语法糖调用,推荐

    @dirhappy
    def test2(name):
        print('this id a directory test2' + str(name))
    test2('lisi')
    
  • 测试结果:
    在这里插入图片描述

2.2、自定义装饰器:

  • 要求:1、兼容可变参数;2、兼容关键字参数;3、打印当前时间。

    import time
    
    def dirsun(fun):
        """ 
        1、*args代表可变参数、**KW代表关键字参数
        2、可变参数不兼容关键字参数
        """
        def sun(*args,**kw):
            print('当前时间'+str(time.time()))
            fun(*args,**kw)
        return sun
    @dirsun
    def test1(name):
        print('this is direction test' + name)
    
    @dirsun
    def test2(name1,name2):
        print('this is direction test' + name1)
        print('this is direction test' + name2)
    
    @dirsun
    def test3(name1,name = 'name',age = 0,beizhu = '长安'):
        print('this is direction test' + name1)
        print('this is direction test' + str(name) + str(age) + str(beizhu))
    
    @dirsun
    def test4(**kw):
        print('this is direction test' + str(kw))
    

    注意:*args代表可变参数、**KW代表关键字参数;可变参数不兼容关键字参数

  • 测试代码:

    test1('张三')
    test2('石敢当',"小福贵")
    test3('小微',name = '张小敬',age = 24,beizhu = '十年陇右兵,九年不良帅')
    test4(name = "崔器",shiji = '陇右九年兵,旅贲军统帅,军帐中攒有贼寇人头84科',age = 28)
    
  • 测试结果:
    在这里插入图片描述

三、列表推导式

  • 定义:序列,集合,字典都是用于列表推导式,可以大大的简化开发
# 列表推导式

list = [1,2,3,4,5,6]

# 测试数组
b = [i * i for i in list]
print(b)
# 条件推到
b = [i * i for i in list if i>3]
print(b)
print('==================================')
# 测试元组
yuanzu = (1,2,3,4,5,6)
a = (i **3 for i in yuanzu)
# 注意元组返回的结果是一个对象,需要转一下
print(tuple(a))
print('==================================')

# 测试集合
jihe = {1,2,3,3,3,4,4,5}
c = {i * 3 for i in jihe}
print(c)
print('==================================')

# 测试字典
zidian = {'name':'zhangsan','age':24,'sex':'男'}
# 注意:一定是字典的items()迭代器,否则遍历不了
d = {key for key,value in zidian.items()}
print(d)
# 将key,value的值交换输出
e = {value:key for key,value in zidian.items()}
print(e)
  • 测试结果:
    在这里插入图片描述

四、None详解

  • None本身就是一个对象,type为NoneType:
    1、空字符串、空[]数组、false等都不是None他们之间没有相等的关系
    2、空字符串、空数组、空集合、false以及None在做if条件判断是都默认返回False

  • 六种基本数据测试

    a = ''
    b = []
    c = set()
    d = False
    e = 0
    f = {}
    
    print(a == None)
    print(b == None)
    print(c == None)
    print(d == None)
    print(e == None)
    print(f == None)
    
    print('===================')
    
    print(a is None)
    print(b is None)
    print(c is None)
    print(d is None)
    print(e is None)
    print(f is None)
    
    print('===================')
    
    print(type(None))
    print('===================')
    if not a:
        print(True)
    else:
        print(False)
    
  • 打印结果:
    在这里插入图片描述
    由上可知,元素为空与None并不等同

  • 如何判断一个对象是否为空:以下是一个特例对象实际上不为空,当事结果判断为空

    class test():
        # def __play__(self):
        #     return 0
        # __len__是python里面的一个特殊函数,用于描述对象的长度,如下当返回值为0 或者 false时,判断语句为假说明此对象为空但实际上此对象并不为空
        def __len__(self):
            return 0
    test = test()
    
    if test:
        print('T')
    else:
        print("F")
    
  • 测试结果:
    在这里插入图片描述
    __len__是python里面的一个特殊函数,用于描述对象的长度,如下当返回值为0 或者 false时,判断语句为假说明此对象为空但实际上此对象并不为空

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值