zoukankan      html  css  js  c++  java
  • Python 函数 高级内容

    在 Python 中, 函数是一等对象。 编程语言理论家把“一等对象”定义为满足四个条件的程序实体:

    1. 在运行时创建
    2. 能赋值给变量或数据结构中的元素
    3. 能作为参数传给函数
    4. 能作为函数的返回结果

    在 Python 中, 整数、 字符串和字典都是一等对象。 后面的课程将重点讨论把函数作为对象的影响和实际应用。

    看一个小小的例子:

    def factorial(n):
        """
        returns n!
        :param n: 
        :return: 
        """
        return 1 if n < 2 else n * factorial(n-1)
    
    print(factorial.__doc__)
    print(type(factorial))
    
    

    把函数视作对象,Python函数是对象,我们先创建一个函数,然后读取它的一个属性,最后确定这个函数本身是 function 类的一个实例。

    接下来呢,展示了函数对象的“一等”本性。 我们可以把 factorial 函数赋值给变量 fact,
    然后通过变量名调用。 我们还能把它作为参数传给 map 函数。 map 函数返回一个可迭代
    对象, 里面的元素是把第一个参数(一个函数) 应用到第二个参数(一个可迭代对象, 这
    里是 range(11)

    fact = factorial
    print(fact)
    print(fact(5))
    print(map(factorial, range(11)))
    print(list(map(fact, range(11))))
    

    有了一等函数或者说是一等对象, 就可以使用函数式风格编程。 函数式编程的特点之一是使用高阶函数。

    什么是高阶函数呢?
    接受函数为参数, 或者把函数作为结果返回的函数是高阶函数。

    最常见的 sorted 函数就是 高阶函数。

    我们做一个简单的例子,根据 字符串 的长度排序。

    fruits = ['strawberry', 'fig', 'apple', 'cherry', 'raspberry', 'banana']
    print(sorted(fruits, key=len))
    

    在函数式编程语言中,最常见的高阶函数有: map、 filter、 reduce, apply(在python3 中已经被删除了)。

    三个问题:

    1. 将列表中每个元素扩大两倍。
    2. 保留列表中的奇数。
    3. 求列表中所有元素的和。

    为了使用高阶函数, 有时创建一次性的小型函数更便利。 这便是匿名函数存在的原因。

    lambda 关键字在 Python 表达式内创建匿名函数。

    然而, Python 简单的句法限制了 lambda 函数的定义体只能使用纯表达式。 换句话
    说, lambda 函数的定义体中不能赋值, 也不能使用 while 和 try 等 Python 语句。

    如果使用 lambda 表达式导致一段代码难以理解,可以这样重构。

    (1) 编写注释, 说明 lambda 表达式的作用。
    (2) 研究一会儿注释, 并找出一个名称来概括注释。
    (3) 把 lambda 表达式转换成 def 语句, 使用那个名称来定义函数。
    (4) 删除注释。

    可调用对象:

    除了用户定义的函数, 调用运算符(即 ()) 还可以应用到其他对象上。 如果想判断对象能否调用, 可以使用内置的 callable() 函数。

    Python 数据模型文档列出了 7 种可调用对象,

    1. 用户定义的函数
      使用 def 语句或 lambda 表达式创建。
    2. 内置函数
      使用 C 语言(CPython) 实现的函数, 如 len 或 time.strftime。
    3. 内置方法
      使用 C 语言实现的方法, 如 dict.get。
    4. 方法
      在类的定义体中定义的函数。

    5. 调用类时会运行类的 new 方法创建一个实例, 然后运行 init 方法, 初始化实例, 最后把实例返回给调用方。 因为 Python 没有 new 运算符, 所以调用类相当于调用函数。
    6. 类的实例
      如果类定义了 call 方法, 那么它的实例可以作为函数调用。
    7. 生成器函数
      使用 yield 关键字的函数或方法。 调用生成器函数返回的是生成器对象。生成器函数在很多方面与其他可调用对象不同,后面会细讲,生成器函数还可以作为协程,后面的课程会细讲。

    Python 中有各种各样可调用的类型, 因此判断对象能否调用, 最安全的方法是使用内
    置的 callable() 函数:

    print([callable(obj) for obj in [int, 'str', str]])
    

    如何让用户自定义一个可调用类型呢?
    不仅 Python 函数是真正的对象, 任何 Python 对象都可以表现得像函数。 为此, 只需实现实例方法 call

    import random
    
    
    class BingoCage:
        def __init__(self, items):
            self._items = list(items) 
            random.shuffle(self._items) 
            
        def pick(self): 
            try:
                return self._items.pop()
            except IndexError:
                raise LookupError('pick from empty BingoCage') 
            
        def __call__(self): 
            return self.pick()
    
    bingo = BingoCage(range(3))
    print(bingo.pick())
    print(bingo())
    print(callable(bingo))
    
    

    实现 call 方法的类是创建函数类对象的简便方式, 此时必须在内部维护一个状态,让它在调用之间可用, 例如 BingoCage 中的剩余元素。
    装饰器就是这样。 装饰器必须是函数, 而且有时要在多次调用之间“记住”某些事 [ 例如备忘(memoization) , 即缓存消耗大的计算结果, 供后面使用 ]

    创建保有内部状态的函数, 还有一种截然不同的方式——使用闭包。 闭包和装饰器会在后面讨论。 下一节课从 函数内省 开始讲解,说说有关函数属性的知识。

  • 相关阅读:
    ubuntu server 12.04中文显示不了
    hustoj升级
    oj资源
    考试系统
    怎样用DOS命令替换文本里的某段字符
    ubuntu一键安装lamp
    Windows Server 2008官方简体中文正式版下载+序列号
    vsphere ubuntu网速很慢
    前端
    (运维)VMwarevCenterServerAppliance5.0安装与部署
  • 原文地址:https://www.cnblogs.com/gznb/p/13200660.html
Copyright © 2011-2022 走看看