• 《流畅的Python》第三部分 把函数视作对象 【一等函数】【使用一等函数实现设计模式】【函数装饰器和闭包】


    第三部分

    第5章 一等函数

    一等对象
    • 在运行时创建
    • 能赋值给变量或数据结构中的元素
    • 能作为参数传递给函数
    • 能作为函数的返回结果

    在Python中,所有函数都是一等对象

    函数是对象

    函数本身是 function 类的实例。

    高阶函数
    • 接受函数为参数,或者把函数作为结果返回的函数
    • 内置高阶函数:map, filter, reduce
    • 列表推导式或生成器推导式同时具有 map 和 filter 两个函数的功能
    类的调用
    • 调用类的过程:运行类的 __ new __ 方法创建一个实例,然后运行 __ init __ 方法,初始化实例,最后返回实例给调用方
    • 如果类定义了 __ call __ 方法,那么类的实例可以作为函数调用*
    • 使用内置函数 callable() 判断对象是否可调用

    ? yield 生成器函数

    函数参数

    可以通过 inspect.signature( func ) 查看函数的参数信息

    def func(a, b, c, *var, d, **kw):
      '''
      a, b, c:  位置参数,关键字参数
      var:      可变参数
      d:        仅限关键字参数
      kw:       可变关键字参数
      '''
      print("a=",a)
      print("b=",b)
      print("c=",c)
      print("var=",var)
      print("d=",d)
      print("kw=",kw)
    
    func('a','b','c','var1','var2',d='d',kw1='kw1',kw2='kw2')
    # a= a
    # b= b
    # c= c
    # var= ('var1', 'var2')
    # d= d
    # kw= {'kw1': 'kw1', 'kw2': 'kw2'}
    
    • 位置参数(POSITIONAL_OR_KEYWORD)
      • 参数定义时,前面的 a, b, c 参数可以直接传入值,并按位置接收
        • def fun(a,b,c)
        • fun(1,2,3)
        • a,b,c = 1,2,3
    • 关键字参数
      • 参数传入的时候可以自定义接受的关键字
        • def fun(a,b,c)
        • fun(c=1,a=2,b=3)
        • a,b,c = 2,3,1
    • 可变参数(VAR_POSITIONAL)
      • 未定义且不带关键字的参数传入,使用可变参数接受形成元组
        • def fun(*var)
        • fun(1,2,3)
        • var = (1,2,3)
    • 仅限关键字参数(KEYWORD_ONLY)
      • 可变参数后面的参数传入,只能带上关键字传入
        • def fun(*var,a)
        • fun(1,2,3,a=4)
        • var,a = (1,2,3),4
    • 可变关键字参数(VAR_KEYWORD)
      • 未定义的关键字参数传入,使用可变关键字参数接受形成字典
        • def fun(a,b,c,**kw)
        • fun(a=1,b=2,c=3,d=4,e=5)
        • a,b,c,kw = 1,2,3,{'d':4,'c':5}

    参数信息保存在 __ code __. 通过 inspect.signature( func ).parameters.items() 可以看到函数的各项参数名称、类型、默认值

    默认值保存在 __ defualt __. 通过 inspect.signature( func ).bind( param_dict ) 可以设定或改变参数的默认值

    函数注解

    def func(a:float, b:'int > 0' =80) -> str
      pass
    

    Python 对注解所做的唯一的事情是,把它们存储在函数的 __ annotations __ 属性里。仅此而已,Python 不做检查、不做强制、 不做验证,什么操作都不做。

    函数式编程

    • operator 模块
      • mul(a,b) 代替 lambda a,b: a*b
      • itemgetter(*idxs) 通过一系列特定位置提取序列中的相应元素
        sel = operator.itemgetter(1, 3)
        print(sel(range(1,10,2)))
        # (3,7)
        
      • attrgetter(*param) 通过一系列属性名称提取对象相应的属性值
    • functools 模块
      • reduce(func, sec) 在 sec 元素上进行 func 参数,与 filter和map 不同
        #阶乘
        def factorial(n):
          return functools.reduce(lambda a,b: a*b, range(1,n+1))
        

    第6章 使用一等函数实现设计模式

    • 将外部函数作为参数传入对象的内部,以达到对象内部使用外部函数的目的

      def list_operater(l,func):
        for i in l:
            func(i,end=' ')
      list_operater(range(5),print)
      # 0 1 2 3 4
      
      promos = [operator.add, operator.mul, operator.sub]
      print(max(functools.reduce(promo, range(3,-2,-1)) for promo in promos))
      # 5
      

    第7章 函数装饰器和闭包

    装饰器

    • 装饰器是一个 “装饰” 函数的函数。
    • 装饰器在被装饰的函数定义之后立即进行运行
    #----------- 1 ----------
    @decorate
    def target():
      print("target")
    
    #----------- 2 ----------
    def target():
      print("target")
    target = decorate(target)
    
    #----------上面两个等同-------------
    def decorate(func):
      def inner():
        print("inner")
      return inner
    
    target()
    # 输出 inner
    
    def dec(func):
        print("dec")
        return func
    @dec
    def func():
        print("func")
    func()
    
    # dec
    # func
    

    变量作用域

    • 在函数体内部有赋值的操作的变量默认为局部变量
    • global 适用于函数内部修改全局变量的值
    • nonlocal 适用于嵌套函数中内部函数修改外部变量的值
    a = 6
    def f2():
      print(a)
    
    def f3():
      print(a)  # 这一行报错 需要定义global或nonlocal
      a = 5
    
    f2()
    f3()
    

    闭包

    • 和使用匿名函数的方式一样,函数内部定义函数,且引用了自由变量。
    def fun():
        times = 0
        def add(t):
            nonlocal times
            times += t
            return times
        return add
    
    cli = fun()
    cli_1 = fun()
    print(cli(10))  # 10
    print(cli(20))  # 30
    print(cli_1(7)) # 7
    print(cli(10))  # 40
    print(cli_1(9)) # 16
    
    标准库中的装饰器
    • @functools.wraps( func )
      • 将 func 的属性复制到被装饰的函数中
    • @functools.lru_cache(maxsize=128, typed=False)
      • 备忘,将耗时的函数结果保存起来,避免传入相同参数时重复计算
      • maxsize 参数指定存储多少个调用结果,旧的丢掉。(应设置为2的幂值)
      • typed 当True时,不同参数类型得到的结果分开存储
    单分派泛函数
    • 根据第一个参数的类型,以不同的方式执行相同操作的一组函数
    • @functools.singleispatch
    @functools.singledispatch
    def judgetype(obj):
        return 'obj'
    
    #装饰器 [basefuncion].register([type]) 的形式
    #函数名称无所谓了,用 _ 简单点
    @judgetype.register(str)
    def _(text):
        return 'str: '+repr(text)
    
    @judgetype.register(numbers.Integral)
    def _(n):
        return 'int: '+repr(n)
    
    @judgetype.register(tuple)
    def _(t):
        return 'tuple: '+repr(t)
    
    @judgetype.register(abc.MutableSequence)
    def _(seq):
        return 'seq: '+repr(seq)
    
    print(judgetype(100))
    print(judgetype('100'))
    print(judgetype((100)))
    print(judgetype([100]))
    
    # int: 100
    # str: '100'
    # int: 100
    # seq: [100]
    
    
    叠放装饰器
    • 将 @d1 和 @d2 顺序应用到 f 函数上,作用相当于 f = d1(d2(f))
    参数化装饰器(工厂函数)
    • def deco(a)
    • @deco(a=True) # 以函数的形式调用装饰器
  • 相关阅读:
    MySQL教程详解之存储引擎介绍及默认引擎设置
    最简单MySQL教程详解(基础篇)之多表联合查询
    Postfix常用命令和邮件队列管理(queue)
    备份数据库
    Docker基本命令
    ASCII码表
    mysql基本了解
    顺序对列,环形队列,反向链式栈
    进制的标识符
    多个线程的时间同步
  • 原文地址:https://www.cnblogs.com/betternow/p/13714699.html
Copyright © 2020-2023  润新知