函数#

1. 参数#

  • 形式参数(parameter):定义括号中的参数,用于接收参数用。

    • 默认参数:含有等式的称为。

      • 不要使用可变类型作为参数的默认值

  • 实际参数(arguement):调用括号中的参数,用于传递给函数用。

# 求 x^n
def power(x, n=2):
    s = 1
    while n > 0:
        n = n - 1
        s = s * x
    return s


print(power(3))

1.1. 可变参数#

参数

表示

调用

可变参数

在参数前面加 *args

本质为一个参数 tuple

关键字参数

在参数前面加 **kwargs

本质为一个参数 dict

命名关键字参数

在关键字参数前面加 *

可加入缺省值

注意:在生成器上使用 * 操作符可能会导致程序跑出内存而崩溃。

# a^2 + b^2 + c^2 + ……
# 计算的对象数目不确定
def calc(*numbers):
    return sum(n * n for n in numbers)


# 也可先组装一个 list,再将该 list 传进去
nums = [1, 2, 3]
print(calc(*nums))

1.2. 关键字参数#

def person(name, age, **kw):
    print('name:', name, 'age:', age, 'other:', kw)


person('Michael', 30)
# 也可先组装出一个 dict,再把该 dict 传进去:
extra = {'city': 'Beijing', 'job': 'Engineer'}
person('Jack', 24, **extra)

1.3. 命名关键字参数#

def person(name, age, *, city, job):
    print(name, age, city, job)


person('Jack', 24, city='Beijing', job='Engineer')

2. 作用域#

函数内定义的变量为局部变量,只能通过所属函数调用函数外定义的变量为全局变量,所有函数均可调用。

  • 当局部变量与全局变量名称相同时,优先调用局部变量

  • 全局变量往往使用下划线命名

Python 使⽤由近及远的 LEGB 顺序来查找对象:locals -> enclosing function -> globals -> builtins

global + 变量名

变量名赋值

全局变量

值可变类型(list,dict,set)

值不可变类型(num,str,tuple)

修改全局变量

可通过函数修改、覆盖

只能使用 global 修改

def spam():
    eggs = 'spam'


def spam_global():
    global eggs
    eggs = 'spam'


eggs = 'global'
spam()
print(eggs)
spam_global()
print(eggs)

3. 返回值#

3.1. Lambda 表达式#

匿名函数 lambda(arg1, arg2, ...) 能接收多个参数,并返回一个表达式的值。

  • 函数定义

def f(x):
    return 2 * x + 1

# 等价于
f = lambda x: 2 * x + 1
  • 函数调用

def calc(a, b, func):
    result = func(a, b)
    return result


num = calc(1, 2, lambda x, y: x + y)
print(num)

4. 改进#

4.1. 偏函数#

偏函数 functools.partial 把一个函数的某些参数设置默认值,返回一个新的函数,减少工作量。

若处理多国语言编写的文本,在比较或排序之前可能会想使用 unicode.normalize('NFC', s) 处理所有字符串 s。若经常这么做,可以定义一个 nfc 函数。

import unicodedata, functools

nfc = functools.partial(unicodedata.normalize, 'NFC')
s1 = 'café'
s2 = 'cafe\u0301'
s1, s2  # ('café', 'café')
s1 == s2  # False
nfc(s1) == nfc(s2)  # True

4.2. 备忘#

functools.lru_cache 是非常实用的装饰器,它实现了备忘(memoization)功能。这是一 项优化技术,它把耗时的函数的结果保存起来,避免传入相同的参数时重复计算。LRU 是 “Least Recently Used” 的缩写,表明缓存不会无限制增长,一段时间不用的缓存条目会被扔掉。

原浪费时间的地方很明显:fibonacci(1) 调用了 3 次,fibonacci(2) 调用了 2 次。

import functools


@functools.lru_cache()
def fibonacci(n):
    return n if n < 2 else fibonacci(n - 2) + fibonacci(n - 1)


if __name__ == '__main__':
    print(fibonacci(4))

functools.lru_cache(maxsize=128, typed=False) 可以使用两个可选的参数来配置。maxsize 参数指定存储多少个调用的结果。缓存满了之后,旧的结果会被扔掉,腾出空间。为了得到最佳性能,maxsize 应该设为 2 的幂。typed 参数若设为 True,把不同参数类型得到的结果分开保存。