函数和函数式编程 - QLGQ/learning-python GitHub Wiki

函数

函数是对程序逻辑进行结构化或过程化的一种编程方法。

函数VS过程

两者都是可以被调用的实体,但是传统意义上的函数或者“黑盒”,可能不带任何输入参数,经过一定的处理,最后向调用者传回返回值。其中一些函数则是布尔类型的,返回一个“是”或者“否”的回答,更确切地说,一个非零或者零值。而过程是简单、特殊、没有返回值的函数。python的过程就是函数,因为解释器会隐式地返回默认值None。

函数返回的对象

返回的对象的数目 Python实际返回的对象
0 None
1 object
>1 tuple
  • 调用函数
    同大多数语言相同,我们用一对圆括号调用函数。

  • 参数组
    Python中允许的函数调用的完整语法为:

    func(positional_args, keyword_args, *tuple_grp_nonkw_args, **dict_grp_kw_args)
  • def语句
    函数是用def语句来创建的,语法如下:

    def function_name(arguments):
        "function_documentation_string"
        function_body_suite

    标题行由def关键字,函数的名字,以及参数的集合(如果有的话)组成。def子句的剩余部分包括了一个虽然可选但是强烈推荐的文档字符串和必需的函数体。

  • 声明与定义比较
    在某些编程语言里,函数声明和函数定义区分开。一个函数声明包括提供对函数名,参数的名字(传统上还有参数的类型),但不必给出函数的任何代码,具体的代码通常属于函数定义的范畴。
    在声明和定义有区别的语言中,往往是因为函数的定义可能和其声明放在不同的文件中。Python将这两者视为一体,函数的子句由声明的标题以及随后的定义体组成的。

  • 前向引用
    和其他高级语言类似,Python也不允许在函数未声明之前,对其进行引用或者调用。但是不会有前向引用的问题,也即引用(调用)函数不需考虑函数定义的先后顺序,因为调用函数一般都是在函数都声明后再调用的。

  • 内部/内嵌函数
    在函数体内创建另外一个函数(对象)是完全合法的,这种函数叫做内部/内嵌函数。
    最明显的创造内部函数的方法是在外部函数的定义体内定义函数(用def关键字),如:

    def foo():
        def bar():
            print 'bar() called'
        print 'foo() called'
        bar()
    foo()
    bar()

    将以上代码置入一个模块中,如inner.py,然后运行,会得到如下输出:

    foo() called
    bar() called
    Traceback (most recent call last):
      File "inner.py", line 10, in <module>
        bar()
    NameError: name 'bar' is not defined

    内部函数一个有趣的方面在于整个函数体都在外部函数的作用域内。如果没有任何对bar()的外部引用,那么除了在函数体内,任何地方都不能对其进行调用,这就是在上述代码执行到最后你看到异常的原因。

    另外一个函数体内创建函数对象的方式是使用lambda语句。如果内部函数的定义包含了在外部函数里定义的对象的引用(这个对象甚至可以是在外部函数之外),内部函数会变成被称为闭包(closure)的特别之物。

函数(与方法)装饰器

装饰器的语法以@开头,接着是装饰器函数的名字和可选的参数。紧跟着装饰器声明的是被修饰的函数和被装饰函数的可选参数。装饰器看起来会是这样:

@decorator(dec_opt_args)
def func2Bdecorated(func_opt_args):
...
  • 无参数的装饰器

    @deco
    def foo(): pass
    
    foo = deco(foo)
  • 有参数的装饰器

    @decomaker(deco_args)
    def foo(): pass
    # 这等价于如下表达式
    foo = decomaker(deco_args) (foo)
    
    @deco1(deco_arg)
    @deco2
    def func(): pass
    # 这等价于如下表达式
    func = deco1(deco_arg) (deco2(func))

    带参数的装饰器decomaker()需要自己返回以函数作为参数的装饰器。换句话说,decomaker()用deco_args做了些事并返回函数对象,而该函数对象正是以foo作为其参数的装饰器。

函数式编程

匿名函数与lambda

lambda [arg1[, arg2, ... , argN]]: expression

lambda表达式返回可调用的函数对象。Python允许用lambda关键字创造匿名函数。

def showAllAsTuple(*z): return z
# 等价于以下表达式
lambda *z: z

b = lambda *z: z
b(23, 'zyx')
(23, 'zyx')
b(42)
(42,)

内建函数

函数编程式的内建函数

内建函数 描述
apply(func[, nkw] [, kw]) 用可选的参数来调用func,nkw为非关键字参数,kw为关键字参数;返回值是函数调用的返回值
filter(func, seq) 调用一个布尔函数func来迭代遍历每个seq中的元素;返回一个使func返回值为true的元素的序列
map(func, seq1[, seq2...]) 将函数func作用于给定序列(s)的每个元素,并用一个列表来提供返回值;如果func为None,func表现为一个身份函数, 返回一个含有每个序列中元素集合的n个元组的列表
reduce(func, seq[, init]) 将二元函数作用于seq序列的元素,每次携带一对(先前的结果以及下一个序列元素),连续的将现有的结果和下一个值作用在获得的随后的结果上,最后减少我们的序列为一个单一的返回值;如果初始值init给定,第一个比较会是init和第一个序列元素而不是序列的头两个元素

map()与多个序列:
map()能以多个序列作为其输入,map()会并行地迭代每个序列。在第一次调用时,map()会将每个序列的第一个元素捆绑到一个元组中,将func函数作用到map()上,当map()已经完成执行的时候,并将元组的结果返回到mapped_seq中,最终是以整体返回的序列。

map(lambda x, y: x + y, [1, 3, 5], [2, 4, 6])
[3, 7, 11]
map(lambda x, y: (x+y, x-y), [1, 3, 5], [2, 4, 6])
[(3, -1), (7, -1), (11, -1)]
map(None, [1, 3, 5], [2, 4, 6])
[(1, 2), (3, 4), (5, 6)]
zip([1, 3, 5], [2, 4, 6])
[(1, 2), (3, 4), (5, 6)]

全局变量与局部变量

global语句

global的语法如下:

global var1[, var2[, ... , varN]]

为了明确地引用一个已命名的全局变量,必须使用global语句。实例如下:

>>> is_this_global = 'xyz'
>>> def foo():
...     global is_this_global
...     this_is_local = 'abc'
...     is_this_global = 'def'
...     print this_is_local + is_this_global
... 
>>> foo()
abcdef
>>> print is_this_global
def
⚠️ **GitHub.com Fallback** ⚠️