Python学习入门
六、函数
目录
6.1 懒惰是⼀种美德
当在⼀个地⽅编写了⼀些代码,但需要在另⼀个地⽅再次使⽤时,就可以使⽤⾃定义函数的⽅式将代码
存储起来。
假设你编写了⼀段代码,它计算⼀些斐波那契数(⼀种数列,其中每个数都是前两个数的和)
6.2 浅谈抽象
抽象可节省⼈⼒,但实际上还有个更重要的优点:抽象是程序能够被⼈理解的关键所在。
6.3 ⾃定义函数
6.3.1 怎么理解函数
函数实际上是:
- 代码的⼀种组织形式
- ⼀个函数⼀般完成⼀项特定的任务
- 函数使⽤:函数需要先定义,使⽤函数,称之为调⽤
- 函数是组织好的,可以重复使⽤的,⽤来实现单⼀或者相关联功能的代码段。
- 函数能提⾼应⽤的模块性和代码的重复利⽤率。
- 其实我们已经接触到了很多python的内建函数,⽐如input(),print(),type()等等。
- 但⾃⼰创建函数也是熟练使⽤python必备的技能之⼀。这种⾃建函数也称作⾃定义函数。
6.3.2 构建规则
我们可以⾃⼰定义⼀个函数,但是需要遵循以下的规则:
1.函数的代码块以def关键字开头,后接函数标识符名称和圆括号()。
2.圆括号⽤来存储要传⼊的参数和变量,这个参数可以是默认的也可以是⾃定义的。
3.函数的第⼀⾏语句可以选择性的使⽤⽂档字符串–⽤于存储⽂档说明。
4.函数内容以冒号起始,并且有强制缩进。
5.return[表达式]结束函数。选择性的返回⼀个值给对⽅调⽤。不带表达式的return相当于返回
None。
6.3.3 回忆⼀下内置函数的调⽤
import math
x = 1 y = math.sqrt
callable(x)
callable(y)
这⾥的 callable() ⽅法⽤来检测对象是否可被调⽤,可被调⽤指的是对象能否使⽤()括号的⽅法调⽤。
从返回结果来看,x是不可调⽤对象,所以调⽤肯定不成功;y是可调⽤对象,结果返回True。
6.3.4 使⽤def语句定义函数
定义函数的格式如下:
def 函数名():
代码
先来定义⼀个函数,让它能够完成打印信息的功能:
def printInfo():
print ('------------------------------------')
print (' ⼈⽣苦短,我⽤Python')
print ('------------------------------------')
printInfo()
再来看个例⼦:
def hello(name):
return 'Hello, ' + name + '!'
上述代码实际上是定义了⼀个名为hello的新函数。它返回⼀个字符串,其中包含向唯⼀参数指定的⼈发
出的问候语。
我们可像使⽤内置函数那样使⽤这个函数:
print(hello('world'))
print(hello('Evan'))
下⾯我们将之前⽤循环写成的斐波那契数列改成⾃定义函数的形式:
def fibs(num):
result = [0, 1]
for i in range(num-2):
result.append(result[-2] + result[-1])
return result
现在直接调⽤函数fifibs就可以实现我们想要的功能啦:
fibs(15)
在这个示例中,num和result也可以使⽤其他名字,但return语句⾮常重要。return语句⽤于从函数返
回值(在前⾯的hello函数中,return语句的作⽤也是⼀样的)
6.3.5 给函数编写说明⽂档
还有另⼀种编写注释的⽅式,就是在def语句后⾯,添加⼀段说明字符串很有⽤。我们将这种放在函数
开头的字符串称为⽂档字符串(docstring),将作为函数的⼀部分存储起来。
为确保其他⼈能够理解程序,要给函数编写⽂档,可以通过以下两种⽅式 :
1.添加注释(以#打头的内容):
2.添加独⽴的字符串
下⾯的代码演示了如何给函数添加⽂档字符串:
def test(a,b):
"""⽤来完成对2个数求和
参数:
a:我们的第⼀个参数⽤来相加
b:这是相加的第⼆个参数
return
很抱歉, 这个函数没有返回值"""
print(a+b)
访问说明⽂档和⽂档字符串可以通过以下形式:
test?
print(test.__doc__)
注意: doc 是函数的⼀个属性。属性名中的双下划线表示这是⼀个特殊的属性。
特殊的内置函数help在交互式解释器中,可使帮助我们获取有关函数的信息,其中包含函数的⽂档字符
串。
help(test)
6.3.6 偶遇参数
现在需要定义⼀个函数,这个函数能够完成2个数的加法运算,并且把结果打印出来,该怎样设
计?下⾯的代码可以吗?有什么缺陷吗?
def add2num():
a = 11
b = 22
c = a+b
print (c)
为了让⼀个函数更通⽤,即想让它计算哪两个数的和,就让它计算哪两个数的和,在定义函数的时候可
以让函数接收数据,就解决了这个问题,这就是函数的参数。
def add2num(a, b):
c = a+b
print (c)
6.3.7 函数的返回值
6.3.7.1 return(返回值)的作⽤
定义了⼀个函数,完成了获取操作,那么函数应该把获取值返回给调⽤函数的⼈,只有调⽤者拥有了这
个返回值,才能够根据当前的值做适当的调整。
def abs_me_2(x):
if x >= 0:
return (x)
else:
return (-x)
6.3.7.2 return的注意事项
在函数中, ⼀旦运⾏到return 这⾏代码, 则函数退出。
def abs_me_3(x):
if x >= 0:
print('return前⾯的代码')
return (x)
print('这⾏代码有没有被运⾏呢?')
else:
return (-x)
print('else这⾏代码有没有被运⾏呢?')
print('这⾏代码呢?'
如你所⻅,跳过了第⼆条print语句。(这有点像在循环中使⽤break,但跳出的是函数。)
6.3.7.3 返回多个值
def test(a, b):
c = a + b
d = a * b
e = a / b
return (c, d, e)
test(3,2)
# (5, 6, 1.5)
c,d,e = test(3,2)
# 相当于c, d, e = 5, 6, 1.5
【重点】6.4 函数的参数详解
6.4.1 值从哪⾥来
定义函数时,你可能⼼存疑虑:参数的值是怎么来的呢?
⼤可不⽤为值从何来⽽费⼼。编写函数旨在为当前程序(甚⾄其他程序)提供服务,⽽我们的职责是确保
它在提供的参数正确时完成任务,并在参数不对时通过异常和断⾔进⾏体现。
6.4.2 形参和实参
在def语句中,位于函数名后⾯的变量通常称为形参,⽽调⽤函数时提供的值称为实参。在很重要的情
况下,我会将实参称为值,以便将其与类似于变量的形参区分开来。
def test(x): # 这⾥的x作为⼀个变量存在, 并不是函数运⾏时候的真实值
return x + 1
test(5) # 这⾥的5, 是真正传⼊进⼊函数的参数
6.4.3 位置参数和关键字参数
前⾯我们使⽤的参数都是位置参数,因为它们的位置⾄关重要——事实上⽐名称还重要。
我们可以来看下⾯这个函数:
def test(a, b, c):
print('a的值是:', a)
print('b的值是:', b)
print('c的值是:', c)
我们可以直接按照参数的顺序赋值,但有时候,参数的排列顺序可能难以记住,尤其是参数很多时。为
了简化调⽤⼯作,可指定参数的名称。
test(1, 2, 3)
test(a=1, b=2, c=3)
test(c=3, b=2, a=1)/
6.4.4 调⽤函数时参数的顺序
关键字参数必须放在位置参数后⾯
我们可结合使⽤位置参数和关键字参数,但必须先指定所有的位置参数,否则解释器将不知道它们是哪
个参数(即不知道参数对应的位置)。
#还是以刚才的函数为例,我们可以这样指定:
test(1, 2, c=3)
#但下⾯的指定⽅式就会出现错误
test(a=1, 2, 3)
test(1, a=2, 3)
test(b=2, a=1)
注意:通常不应结合使⽤位置参数和关键字参数,除⾮我们已经知道这样做的后果。⼀般⽽⾔,除⾮必
不可少的参数很少,⽽带默认值的可选参数很多,否则不应结合使⽤关键字参数和位置参数。
所以我们可以发现关键字参数的⼀些优势:
1.使⽤名称指定的参数,有助于澄清各个参数的作⽤。这样,函数调⽤不再像下⾯这样怪异⽽神秘。
2.使⽤关键字参数使每个参数的作⽤清晰明了。另外,参数的顺序错了也没关系。
另外,关键字参数最⼤的优点还在于可以指定默认值。
6.4.5 默认参数
先来编写⼀个求幂值的函数:
def power(x, y):
n = 1
i = 0
while i < y:
n *= x
i += 1
return n
因为我们⼤多数时候,都是需要求平⽅, 因此后⾯的参数取2的可能性最⼤:
def power(x, y=2): # y的默认值是2
n = 1
i = 0
while i < y:
n *= x
i += 1
return n
像这样给参数指定默认值后,调⽤函数时可不提供它!可以根据需要:
⼀个参数值也不提供
提供部分参数值
提供全部参数值
注意:
必选参数在前,默认参数在后,否则会报错。
默认参数降低了函数调⽤的难度,⽽⼀旦需要更复杂的调⽤时,⼜可以传递更多的参数来实现。⽆
论是简单调⽤还是复杂调⽤,函数只需要定义⼀个。
6.4.6 收集参数
6.4.6.1 ⼀个星号
有时候,允许⽤户提供任意数量的参数很有⽤。例如在下⾯的例⼦中,我想存储多个姓名,这样做会更
加符合实际应⽤场景:
store(data, name1, name2, name3)
这时候我们要允许提供任意数量的姓名,我们可以像下⾯这样对函数进⾏定义:
def print_params(*params):
print(params)
#我们在这⾥虽然看起来只指定了⼀个参数,但会发现在参数前⾯有个星号,这时候参数变为可变⻓参数,函数可以接收1个、2个到任意个,还可以是0个值作为参数。在例⼦中看看传⼊这类参数的函数的使⽤和调⽤:
print_params('Python')
# ('Python',)
#这⾥打印的是⼀个元组,因为⾥⾯有⼀个逗号。这样的话是不是说,前⾯有星号的参数将被放在元组中呢?来试试复数的params:
print_params(1, 2, 3)
#从结果可以看出参数前⾯的星号将提供的所有值都放在⼀个元组中,也就是将这些值收集起来。再来编写⼀个函数:
def print_params_1(title, *params):
print(title)
print(params
#并尝试调⽤它:
print_params_2('Params:', 1, 2, 3)
#所以,星号意味着收集余下的位置参数。如果没有可供收集的参数,params将返回空元组。
print_params_2('Params:')
#还记得之前我们写的⼀个函数,⽤来计算列表的加和么?现在我们想不需要传⼊列表,同样实现这样⼀个功能,可以传⼊任意个参数,然后计算参数的加和:
def sum_me(x_list):
n = 0
for i in x_list:
n += i
return n
#现在我们想这样做:
sum_me(2, 3, 4, 5, 6, 7)
但现在的函数不允许,这时候我们在参数前⾯加个星号:
def sum_you(*x_list):
n = 0
for i in x_list:
n += i
return n
6.4.6.2 两个星号
带星号的参数可放在其他位置,⽽不是⼀定要放在最后,但在这种情况下我们需要做些额外的⼯作:
def test(x, *y, z):
print(x, y, z)
test(1,2,3,4,5,z=6)
# 1 (2, 3, 4, 5) 7
test(1,2,3,4,5,6)
# 报错
#此时,⼀个星号不会收集关键字参数,要收集关键字参数,可使⽤两个星号。
def test_1(**params):
print(params)
test_1(a=1, b=2, c='qqq', d=True)
⼀个星号就是打包成元组传⼊进来,两个星号就是打包成字典传⼊进来。
这样,我们得到的就是⼀个字典⽽不是元组。
那么如果普通参数,可变⻓参数,可变⻓关键字参数结合在⼀起定义会怎么样呢?
def test_2(a, b, *args, **kwagrs):
"""可变参数演示示例"""
print ("a =", a)
print ("b =", b)
print ("args =", args)
print ("kwargs: ")
print(kwargs)
#我们试试加⼊实参:
test_2(1,'xxx')
test_2(1,'xxx',2,3)
test_2(1,'xxx',2,3,4,5,6,7,100,1000,'asdfg')
test_2(1,2,3,4,5,m=6,n=7,p=8)
test_2(1,2,3,m=6,n=7,p=8,4,5)
#注意:这⾥同样遵循关键字参数必须在位置参数之后的顺序。
6.5 作⽤域
函数变量的作⽤域其实就是平时我们所说的变量可⻅性。 在python当中,程序的变量并不是在任何
位置都能被访问,访问权限取决于变量是在什么位置赋值的。 变量的作⽤域决定了变量在哪⼀部分程序
可以被访问。 python的作⽤域⼀共有4种:
- L (Local)局部作⽤域
- E (Enclosing)闭包函数外的函数中
- G (Global)全局作⽤域
- B (Built-in)内建作⽤域
以 L --> E --> G --> B 的规则查找:
即在局部找不到,则会去局部外的局部找,⽐如闭包。再找不到,就会去全局找,再者则会去内建中
找。
内建作⽤域
x = int(2.9)
全局作⽤域
y = 2
闭包和局部作⽤域
def outer(n):
o_count = n # 闭包外的局部作⽤域
def inner():
return o_count + 1 # 闭包的局部作⽤域
return inner()
print(outer(10))
#但你直接调⽤o_count是不⾏的:
o_count
# NameError: name 'o_count' is not defined
python中只有模块(module),类(class)以及函数(def ,lamda)才会引⼊新的作⽤域,其他的代码块
(如if/else/elif/、for/while、try/except等)是不会引⼊新的作⽤域的,也就是说这些语句内定义的
变量,外部也可以访问,如下代码:
if True:
...
x = 'I am from CDA'
...
x
实例中 x变量定义在 if 语句块中,但外部还是可以访问的。
如果将 x定义在函数中,则它就是局部变量,外部不能访问:
def test():
...
x_inner = 'I am from Python'
...
return x_inner
这⾥报错的原因在于:对于函数外部⽽⾔,x_inner没有被定义过,也就是说Python找不到x_inner这个
变量。这是因为x_inner只是⼀个局部变量,它的作⽤范围只在它的地盘上 “test()” 函数的定义范围内有
效,出了这个范围,就不属于x_inner的作⽤域了,它将不起任何作⽤。注意⼀下,在函数⾥⾯定义的参数以及变量,都称为局部变量,出了这个函数,这些变量就是⽆效的。事实上的原理是,Python在运⾏函数的时候,利⽤栈(Stack)进⾏存储,当执⾏完函数之后,函数中所有的数据都会被⾃动删除。所以在函数外边是⽆法访问到函数内部的局部变量的。
6.6 全局变量和局部变量
定义在函数内部的变量拥有⼀个局部作⽤域,定义在函数外的拥有全局作⽤域。 局部变量只能在其被声
明的函数内部访问,⽽全局变量可以在整个程序范围内访问。调⽤函数时,所有在函数内声明的变量名
称都将被加⼊到作⽤域中。如下实例:
total = 0 # 这是⼀个全局变量
# 返回2个参数的和
def sum(arg1,arg2):
total = arg1 + arg2 # total 在这⾥就是局部变量
print('函数内是局部变量:',total)
return total
#调⽤sum函数
sum(11,22)
print("函数外是全局变量:",total)
在函数外边定义的变量叫做全局变量
全局变量能够在所有的函数中进⾏访问
如果在函数中修改全局变量,那么就需要使⽤global进⾏声明,否则出错
如果全局变量的名字和局部变量的名字相同,那么使⽤的是局部变量的,⼩技巧:强⻰不压地头蛇
6.7 global关键字
⼩姐姐问:⼀个⾃然⽽然的需求, 能不能在函数内部修改全局变量呢?
⼩哥哥答:函数内部可以调⽤全局变量的值, 但是不能修改哟~
a = 1
def f():
a += 1
print (a) f
通过上述例⼦,我们可以发现,函数中修改全局变量可能导致程序可读性变差、出现莫名其妙的bug、
代码的维护成本⾼。因此不建议在函数内部修改全局变量。
如果⼩姐姐⾮要在函数内部修改全局变量, 怎么办呢? ⼩哥哥可以这样做:
# 定义全局变量
a = 1
def f():
global a # 需要使⽤全局变量⽤global关键字说明
a += 1
print (a) f()
其实,我们在函数中不使⽤global声明全局变量时就不能修改全局变量的本质是不能修改全局变量的指
向,即不能将全局变量指向新的数据。
对于不可变类型的全局变量来说,因其指向的数据不能修改,所以不使⽤global时⽆法修改全局变量。
对于可变类型的全局变量来说,因其指向的数据可以修改,所以不使⽤global时也可修改全局变量。
⽐如下⾯这段代码执⾏后显然是会报错的,因为我没有声明:
a = 1 # 不可变的
def f():
a += 1
print (a) f()
现在我们把a变成可变序列:
li = []
def f(x):
li.append(x)
li = [1,]
def f2():
li.append(1)
print (li)
f2()
6.8 内嵌函数和nonlocal关键字
6.8.1 内嵌函数
Python的函数定义可以是嵌套的,也就是允许在函数内部创建另⼀个函数,这种函数叫做内嵌函数或内
部函数。
def func_1():
print("func_1()正在被调⽤...")
def func_2():
print("func_2()正在被调⽤...")
func_2()
func_1()
这是函数嵌套最简单的例⼦。关于内部函数的使⽤,有⼀个⽐较值得注意的地⽅,就是内部函数整个作
⽤域都在外部函数之内。就像例⼦中的func_2()整个函数的作⽤域都在func_1()⾥⾯。
需要注意的地⽅是,除了在func_1()这个函数可以调⽤func_2()这个内部函数,出了func_1()就没有地⽅
可以调⽤func_2() 了。如果⾮要尝试,那报错是在所难免的了
6.8.2 nonlocal关键字
同样,想要在内嵌的函数局部更改局部外局部的变量,就需要⽤到nonlocbal关键字:
def outer():
num = 10
def inner():
nonlocal num # nonlocal关键字声明
num = 100
print(num)
inner()
print(num)
outer()
【难点】6.9 闭包
在作⽤域⼩节中,我们提到了闭包这⼀名词。
闭包是函数式编程的重要语法结构,Pyhon中的闭包从形式上定义为:如果在⼀个内部函数⾥,对在外
部作⽤域(但不是全局作⽤域)的变量进⾏引⽤,那么内部函数就被认为是闭包。
所以当时我们说闭包的作⽤域是闭包函数外(但不是全局)的函数中(外部函数中)。
def funcX(x):
def funcY(y):
return x *y
return funcY
i= funcX(8)
i(5)
funcX(8)(5)
如果在⼀个内部函数⾥(funcY)对外部作⽤域的,但不是全局作⽤域的变量进⾏引⽤,这⾥特指x(它
在funcX区域中,但不在全局),这个内部函数funcY就是⼀个闭包。
需要注意的是,funcY也是定义在函数内部的函数,它的概念就是由嵌套函数的内部函数概念引申⽽
来,因此,内部函数也不能在外部调⽤。
【难点】6.10 递归
递归属于⽐较⾼级的范畴,但是对于想要写出漂亮程序的程序员来说,是⼀个⾮常好的编程思路。⽣活
中有很多递归的例⼦:⽐如汉诺塔游戏、结构树的定义、谢尔宾斯基三⻆形、⼥神⾃拍。
前边我们已经学过函数的嵌套了。那么⼀个函数内部可以嵌套其他函数, 函数内部如果再嵌套⼀个函数
⾃⼰, 就是我们所说的递归函数了。
在程序上,递归实质上是函数调⽤⾃身的⾏为
def recursion():
return recursion()
recursion()
显然,这样去定义是毫⽆意义的,虽然与刚才的 “递归” 定义⼀样。但在运⾏⼀段时间后,这个程序崩溃
了(出现了异常)。
从理论上说,这个程序将不断运⾏下去,但每次调⽤函数时,都将消耗内存。因此,在函数调⽤次数达
到⼀定程度后(且之前的函数调⽤未返回),将耗尽所有的内存空间,导致程序终⽌并显示错误消息
“超过最⼤递归深度” 。
在这个函数中的递归成为⽆穷递归(类似 while True 打头,并且不包含 break 和 return 语句的循环,
我们成为⽆限循环⼀样),从理论来看它永远不会结束。⽽我们希望的是有意义的递归函数,这样的递
归函数通常包含以下两个部分。
基线条件:针对最⼩的问题,满⾜这种条件时函数将直接返回⼀个值。
递归条件:包含⼀个或者多个调⽤,这些调⽤旨在解决问题的⼀部分。
这⾥的关键点是,我们通过将问题分解为较⼩的部分,避免递归没完没了,因此问题终将被分解成基线
条件可以解决的最⼩问题。
如何理解函数调⽤⾃身?
每次调⽤函数时,都将为此创建⼀个新的命名空间。这就意味着函数在调⽤⾃身时,是两个不同的
函数。我们可以把它理解为,是两个不同的版本,即命名空间不同的同⼀函数在做交流。我们也可以将其
视为两个属于相同物种的动物在彼此交流。
6.10.1 阶乘和幂
⼀起来计算数字n的阶乘:
#我们可以使⽤循环的⽅式:
def factorial(n):
result = 1
for i in range(1,n+1):
result *= i
return result
# 或者我反向相乘,先将result设置为n,再将其依次乘以1到n-1的每个数字,最后返回result。
def factorial(n):
result = n
for i in range(1, n):
result *= i
return result
我们可以很容易发现阶乘的规律:
1! = 1
2! = 2 × 1 = 2 × 1!
3! = 3 × 2 × 1 = 3 × 2!
4! = 4 × 3 × 2 × 1 = 4 × 3!
...
n! = n × (n-1)!
下⾯来考虑如何使⽤递归函数来实现这个定义。理解这个定义后,实现起来其实⾮常简单。
if num > 1:
return num * calnum(num-1)
else:
return 1
别忘了函数调⽤calnum(num)和calnum(num – 1)是不同的实体。
递归函数与循环结构相⽐,在⼤多数情况下,使⽤循环的效率可能更⾼。然⽽,在很多情况下,使⽤递
归的代码可读性更⾼,且有时要⾼得多,尤其对递归的定义有了深⼊理解之后。另外,虽然我们完全能
够避免编写递归函数,但作为程序员,我们必须能够读懂其他⼈编写的递归算法和函数。
【重点】6.11 lambda匿名函数
6.11.1 lambda
lambda能创建⼀个匿名函数,程序员觉得每次创建⼀个函数,即使是很简单的函数也需要去起名太麻
烦了。
于是就有了lambda,它可以直接写进⼀个需要简单函数的地⽅,⽽不需要单独去进⾏定义⼀个函数。
6.11.2 lambda的标准语法
⽤lambda关键词能创建⼩型匿名函数,这种函数得名于省略了⽤def声明函数的标准步骤。
lambda函数的语法只包含⼀个语句,如下:
然⽽,这种简单的句法限制了 lambda 函数的定义体只能使⽤纯表达式。换句话说,lambda 函数的定
义体中不能赋值,也不能使⽤ while和 try 等 Python 语句。
6.11.3 lambda函数的使⽤场景
应⽤场景:函数作为参数进⾏传递
Lambda函数能接收任何数量的参数,但只能返回⼀个表达式的值
匿名函数不能直接调⽤print,因为lambda需要⼀个表达式
6.11.3.1 把函数功能屏蔽
⽐如,创建⼀个让程序休眠的程序
6.11.3.2 作为⾼级函数的参数
我们使⽤Python中⼏个定义好的全局函数:map,fifilter,sorted
map
map(self, /, *args, **kwargs)
创建⼀个迭代器,该迭代器使⽤来⾃每个可迭代项的参数计算函数。
简单来说,map() 会根据提供的函数对指定序列做映射。第⼀个参数 function 以参数序列中的每⼀个
元素调⽤ function 函数,返回包含每次 function 函数返回值的新列表。
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
list(map(lambda x:x*2+10, a))
map() 函数接收两个参数,⼀个是函数,⼀个是iterable,map将传⼊的函数依次作⽤到序列的每个元
素,并把结果作为新的iterator返回。
由于结果是⼀个iterator,⽽iterator是惰性序列,因此需要通过list() 函数让它把整个序列都计算出来并
返回⼀个list
sorted
sorted(iterable, /, *, key=None, reverse=False)
sorted() 函数也是⼀个⾼阶函数,对所有可迭代的对象进⾏排序操作。
它还可以接收⼀个key函数来实现⾃定义的排序,例如按绝对值⼤⼩排序。
a = [2, 5, 6, 1, 3, 4, 55, 22, 77, 8, 1, 2, 3, 4, 10]
sorted(a)
sorted(a,reverse=True)
sorted(a, key=lambda x:x%2==1)
sorted(a, key=lambda x: abs(5 - x))
6.12 ⼩结
我们介绍了抽象的基本知识以及函数:
抽象:抽象是隐藏不必要细节的艺术。通过定义处理细节的函数,可让程序更抽象。
函数定义:函数是使⽤def语句定义的。函数由语句块组成,它们从外部接收值(参数),并可能返回⼀个
或多个值(计算结果)。
参数:函数通过参数(调⽤函数时被设置的变量)接收所需的信息。在Python中,参数有两类:位置参数
和关键字参数。通过给参数指定默认值,可使其变成可选的。
作⽤域:变量存储在作⽤域(也叫命名空间)中。在Python中,作⽤域分两⼤类:全局作⽤域和局部作⽤
域。作⽤域可以嵌套。
递归:函数可调⽤⾃身,这称为递归。可使⽤递归完成的任何任务都可使⽤循环来完成,但有时使⽤递
归函数的可读性更⾼。
函数式编程:Python提供了⼀些函数式编程⼯具,其中包括lambda表达式以及函数map、fifilter和
sorted.