函数详解
定义¶
- 以
def
关键词开头, 后街函数标识符名称和圆括号()
- 任何传入参数和自变量必须放在圆括号中间
- 函数的第一行语句可以选择性的使用文档字符串—用于存放函数说明
- 函数内容以冒号起始并且缩进
return [表达式]
结束函数, 选择性的返回一个只给调用方; 不带表达式的return
相当于返回None
参数传递¶
在Python
中, 类型属于对象, 变量是没有类型的, 如a = [1, 2, 3]
以上代码中, [1, 2, 3]
是list
类型, 而a
是没有类型的,他仅仅是一个对象的引用(指针)
可更改与不可更改对象¶
- 不可变类型: string, tuple和number是不可更改对象
- 可变类型: list, dict等是可更改对象
传递参数过程:
- 不可变类型: 类似值传递
- 可变类型: 类似引用传递
补充: 不可变对象是指对象本身不可变, 但变量的对象引用可变而可变对象是指对象内容可变, 但变量的对象引用不会改变
参数类型¶
-
必备参数(位置参数)
必备参数必须以正确的顺序传入函数, 调用时的数量必须和声明时一样
1
2def func(param):
pass -
默认参数
调用函数时, 默认参数的值如果没有传入, 则被认为是默认值
1
2def func(param1, param2=value):
pass -
可变参数(不定长参数)
可能一个函数能处理比当初声明时更多的参数
1
2def func(*param):
pass参数会以一个元组的形式被传入函数, 如果在调用函数时已有一个元组或列表, 则如此
func(*tuple\*list)
调用 -
关键字参数
关键字参数允许传入0或任意个含参数名的参数, 这些关键字参数在函数内部自动组装为一个
dict
1
2def person(name, age, **kw):
print("name:", name, "age:", age, "other:", kw)如同可变参数, 也可以通过
person(name, age, **dict)
将一个已有的字典传入函数 -
命名关键字参数
命名关键字参数可以限制关键字参数的关键字
1
2def person(name, age, *, city, job):
print(name, age, city, job)同时命名关键字参数还可以设定默认值
def person(name, *, city="Beijing", job)
匿名函数¶
Python
使用lambda
来创建匿名函数
lambda
只是一个表达式, 函数体比def
简单很多lambda
的主体是一个表达式, 而不是一个代码块lambda
函数拥有自己的命名空间, 且不能访问自由参数列表之外或全局命名空间里的参数- 虽然
lambda
看起来只能写一行, 却不等同于C
或C++
的内联函数
语法: lambda [arg1[, arg2, ...argn]]: expression
变量作用域¶
-
全局变量
定义在函数外的拥有全局作用域, 全局变量可以在整个程序范围内访问
-
局部变量
定义在函数内的拥有局部作用域, 局部变量只能在其被声明的函数内部访问
调用函数时, 所有在函数内声明的变量名称将被加入到作用域中
注:
- 全局变量想作用在函数内, 需加
global
声明 - 外部域变量想作用在内部域, 需加
nonlocal
声明(外部域和内部域是相对概念, 因此在局部域中使用全局变量既可以用global
也可以用nonlocal
声明) - 函数的方法名也可以作为另一个函数的参数
命名空间¶
- 内置名称空间 (
Python
语言内置的名称空间, 如内置函数名, 异常名) - 全局名称 (模块[一个
.py
文件]中定义的名称, 包括函数名, 类名, 导入的模块名, 以及模块级的变量和常量) - 局部名称 (函数或类中定义的名称, 包括参数和内部定义的变量名)
作用域¶
- L(Local) 当前域 一个函数/方法内部
- E(Enclosing) 外部域 一般在类中或嵌套函数中, 如
A
中包含了B
这个函数, 则在A
下定义的变量对于B
来说就是外部域的变量 - G(Global) 全局域 当前文件的全局变量
- B(Built-in) 内置域 包含了内建的变量/关键字等
高阶函数¶
函数名也是变量, 或者说函数名是指向具体函数对象的指针变量(从C的角度理解, 不太一样; C中有类型的是一个个具体的变量, 而Python中有类型的是抽象的对象, 变量只是一个名称, 无类型), 因此, 我们可以创建一个变量直接用函数名赋值, 此时该变量也指向该函数名指向的函数, 相当于给函数起别名
定义¶
一个函数接收另一个函数作为参数, 这种函数就被称为高阶函数
高阶函数举例¶
map
/reduce
¶
语法: map(function, Iterable, …)
参数: function – 函数; iterable – 一个或多个序列
返回值: Python2.x
返回列表, Python3.x
返回迭代器(所要处理的数据可能过大, 所以python3改为返回一个迭代器)
功能: 将传入的函数作用于序列的每一个元素, 并以Iteraor
返回
例:
1 | def f(x) |
reduce
函数已迁移至functools
模块, 如要使用, 需先导入
语法: reduce(function, itearable[, initializer])
参数: function
– 函数, 有两个参数; iterable
– 可迭代对象; initalizer
– 可选, 初始参数
返回值: 返回函数计算结果
功能: 将函数作用于序列上, 且将上一个返回值于序列的下一个元素做累积计算, 即reduce(f, [x1, x2, x3]) = f(f(x1, x2), x3)
例:
1 | # 一个将`str`转换为`int`的函数 |
综合运用:
1 | # 一个将str转换为num的程序 |
filter¶
语法: filter(function, iterable)
参数: function
– 判断函数, iterable
– 可迭代对象
返回值: Python2
返回列表, Python3
返回迭代器
功能: 将传入的函数依次作用于每个元素, 然后根据返回值决定保留还是丢弃该元素
例:
1 | # 用filter求素数 |
sorted¶
语法: sorted(iterable, cmp=None, key=None, reverse=False)
参数: iterable
– 可迭代对象; cmp
–比较的函数, 这个具有两个参数, 参数的值都是从可迭代对象中取出的, 此函数必须遵守的规则为, 大于则返回1, 小于则返回-1, 等于则返回0; key
– 主要是用来进行比较的元素, 只有一个参数, 具体的函数的参数就是取自于可迭代对象中, 指定可迭代对象中的一个元素来进行排序; reverse
–排序规则, True
为降序, False
为升序(默认)
返回值: 返回重新排序的列表
装饰器¶
返回函数¶
高阶函数除了可以接受函数作为参数外, 还可以把函数作为返回值返回
如: 实现一个可变参数的求和
1 | def calc_sum(*args): |
一般可以按以上的方式实现, 但如果此时不需要立刻求和, 而是在后面的代码中, 根据需要再计算, 则可以返回求和的函数:
1 | def lazy_sum(*args): |
闭包¶
在上述程序中, lazy_sum
中定义了函数sum
, 并且宿命
可以引用外部函数的参数和局部变量, 当lazy_sum
返回函数sum
时, 相关的参数和变量豆包存在返回的函数中, 这种称为闭包
注: 使用闭包时牢记 返回函数不要引用任何循环变量, 或者后续会发生变化的变量
如果必须使用, 则在创建一个函数, 用该函数的参数绑定循环变量当前的值
装饰器¶
如果我们想在代码运行期间动态增加功能, 而不修改函数的定义, 这种方式称为装饰器(例如日志功能, 在程序运行时记录运行的数据)
语法: 在一个函数定义的上一行 @decorator
(相当于执行, func = decorator(func)
)
功能: 相当于在函数运行时附带另一个函数功能, 从程序语句来看, 就是将指向原函数对象的变量指向经装饰器装饰后的函数对象
注: 如果想要让装饰器也可以接受参数, 则在原装饰器函数的外部再写一层函数, 使得返回的是带参数的装饰器对象(或者不使用@
语法, 使用装饰器原理的语句)