函数定义
以下是简单的规则:
- 函数代码块以 def关键词 开头,后接 函数标识符名称 和 圆括号()。
- 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
- 函数内容以冒号起始,并且缩进。
- return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。
语法
1 | def 函数名(函数列表): |
函数调用
定义一个函数:给了函数一个名称,指定了函数里包含的参数,和代码块结构。
这个函数的基本结构完成以后,你可以通过另一个函数调用执行,也可以直接从 Python 命令提示符执行。
参数传递
在 python 中,类型属于对象,而变量是没有类型的,它只是一个引用,可以代表任何对象
可更改(mutable)与不可更改(immutable)对象:
在 python 中,strings, tuples, 和 numbers 是不可更改的对象,而 list,dict 等则是可以修改的对象。
- 不可变类型:新建了一个对象赋值给变量,原对象被丢弃
- 可变类型:修改了对象
- python的参数传递:
- 不可变类型:类似于值传递,即拷贝传值,不影响原对象
- 可变类型:类似于引用传递,影响原对象
- python 中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。
参数
python中的正式参数类型:
- 必需参数
- 关键字参数
- 默认参数
- 不定长参数
必需参数
必需参数须以正确的顺序传入函数。调用时的数量必须和声明时的一样。
关键字参数
关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。
- 使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。
默认参数
与C++中的默认参数一致,调用函数时,如果没有传递参数,则会使用默认参数。
不定长参数
也称收集参数,你可能需要一个函数能处理比当初声明时更多的参数,这些参数叫做不定长参数。
单星号*(tuple)
加了 星号* 的参数会以 元组(tuple) 的形式导入,存放所有未命名的变量参数。
- 若没有指定,则为空元组
1 | def printinfo(*vartuple, end = "\n"): |
双星号**(dict)
加了 两个星号** 的参数会以 字典(dict) 的形式导入。使用方法与上面类似。
总结
- 星号* 可以单独出现,但是如果单独出现 星号* 后的参数必须用关键字传入。
- 其实 星号* 起到“打包”作用,将多个参数打包成一个元组
- 星号* 在形参中的作用是“打包”,在实参中的作用是“解包”
- 若作为不定长参数传入元组和字典时,要加上星号* 和 双星号**,即传入时要解包,否则元组和字典只会被当作一个参数
变量作用域
局部变量
定义在函数内部的变量是局部变量,它的作用域:函数内部,不能在函数外部被引用
全局变量
与局部变量相对,拥有更大的作用域,可以在函数中访问
- 函数中可以访问全局变量,但是不能修改(Python会在函数内部新建了一个局部变量,真正的全局变量不被改变)
global关键字
Python使用 屏蔽(shadowing) 保护全局变量:一旦函数内部试图修改全局变量,那么就会新建一个名字一样的局部变量代替,保护全局变量。
如果你还是要坚持修改,使用 global关键字 声明该全局变量,即可在函数内部修改全局变量。
内嵌函数
Python的函数定义支持嵌套,定义在别的函数内部的被称为内嵌函数或者内部函数
- 内部函数整个作用域在外部函数之内,只有在外部函数里才能调用内嵌函数
- 内部函数可以引用外部函数的局部变量,此时内部函数称为 闭包 ,但是与全局变量类似,不能在内部函数修改外部函数的局部变量,且不能使用 global 修改,可以使用 nolocal关键字 修改
LEGB原则
变量查找的顺序按照 L→E→G→B
- LEGB含义解释:
- L-Local:函数内的名字空间
- E-Enclosing function locals:嵌套函数中外部函数的名字空间
- G-Global:函数定义所在模块的名字空间
- B-Builtin:Python内置模块的名字空间
闭包
闭包(closure)是语法闭包(lexical closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。
- Python中的闭包表现在:如果一个内部函数里,对在外部作用域但不是在全局作用域的变量进行引用,那么内部函数就是闭包
- 在闭包中,外部函数的局部变量对应内部函数的局部变量,相当于全局变量与局部变量的关系,可以访问不能修改,但是可以使用 nolocal关键字 修改
装饰器
装饰器(decorator) 的功能:将被装饰的函数当作参数传递给装饰器对应的函数(名称相同的函数),并返回包装后的被装饰的函数
-
@语法糖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17# 给eat函数加上日志
def log(func):
def wrapper():
print("开始调用eat函数")
func()
print("结束调用eat函数")
return wrapper
# @log 等价于 log(eat())
@log
def eat():
print("开始吃了")
>>> eat()
开始调用eat函数
开始吃了
结束调用eat函数- 可以省去手动将eat()传递给log()再将返回值重新赋值的过程(eat = log(eat))
-
如果使用 @语法糖 时候,eat()有参数,最好使用不定长参数,不然在修改eat()的参数时,也要修改装饰器log()
-
@语法糖也可以嵌套使用
函数式编程
函数式编程(funtional programming),是一种编程范式,它将电脑运算视为函数运算,并避免使用程序状态以及易变对象。
- 其中,λ演算(lambda calculus) 为该语言最重要的基础。而且,λ演算的函数 可以接受函数当作输入(引数)和输出(传出值)。
lambda
Python使用 lambda关键字 来创建 匿名函数,简化函数定义的过程。
- 基本语法:使用 冒号: 分隔函数的参数及返回值
- 冒号左边放参数,使用 逗号, 隔开
- 冒号右边是函数的返回值
- 执行完 lambda 返回的是一个函数对象,如果要对它进行调用,只需要给它绑定一个临时的名字
1
2
3lambda x,y : x**y g =
3,4) g(
81
filter()
filter()函数是一个过滤器,它的作用是在海量得数据里面提取出有用得信息
class filter(object)
| filter(function or None, iterable) --> filter object
|
| Return an iterator yielding those items of iterable for which function(item)
| is true. If function is None, return the items that are true.
- filter有两个参数:第一个是一个函数或者None
- 如果是一个函数的话,则把第二个可迭代对象里的每一个元素作为函数的参数进行计算,筛选出返回True的元素
- 如果是None,则直接将第二个参数中为True的值筛选出来
- filter()返回的是一个迭代器对象
1 | # 筛选出0~9中的奇数 |
map()
map()会根据提供的函数对指定序列做映射。
class map(object)
| map(func, *iterables) --> map object
|
| Make an iterator that computes the function using arguments from
| each of the iterables. Stops when the shortest iterable is exhausted.
- map有两个参数:一个函数和一个可迭代对象,将可迭代对象的每一个元素作为函数的参数进行运算加工,直至可迭代序列每个元素都加工完毕,即 将序列的每一个元素通过函数进行映射
- map()第二个参数是不定长参数,支持多个可迭代对象。map()会从所有可迭代对象各取一个元素组成元组,类似于zip()函数,然后将元组传递给func(第一个参数)
- 以短的可迭代对象为止
- map()返回的是一个迭代器