如果你学过其他编程语言,就知道,函数可以将要实现的一个个功能分别合并成一个个小块,要使用的时候只需调用即可。比如,我们要求 1 + 2 + 3 + . . . + 100 1+2+3+...+100 1+2+3+...+100,很简单,写个循环就可以了,那我们想再求 1 + 2 + . . . + 1000 1+2+...+1000 1+2+...+1000呢,你可能会想,把上面那个的代码复制粘贴,再改改几个数就行了,但是,假如我们还要你求 1 + . . . + 2000 1+...+2000 1+...+2000, 1 + . . . + 3000 1+...+3000 1+...+3000呢,如果还复制粘贴,是不是觉得很麻烦。因此,我们希望,可以用一句代码实现这样一个功能:从a一直加到b,我们只需告诉它a和b是什么就行了。这时,函数就可以上场了,我们把a和b的值告诉函数,再写上自己要实现的功能,然后函数内部就会自动去帮我们完成 a + . . . + b a+...+b a+...+b 。这样,我们只要更改不同的参数a和b,就能实现上述需求了,是不是很简单,接下来我们就学习如何设计一个符合自己需求的函数。
要调用一个函数,首先得有这个函数才行,因此我们要先声明(定义)一个函数。
在python中,声明一个函数的形式一般为:
def <函数名>(参数列表):
<函数语句>
return <返回值>
return
语句也可以没有,在这两种情况下函数都默认返回 None
;,
隔开,有些函数也可以没有参数列表。注意没有参数时,也不能省略括号和冒号():
例如:
def hello(): #无参数
print('hello world')
def Sum(a, b): #计算 a +...+ b
s = 0
while a <= b:
s = s + a
a += 1
return s #有返回值
实际上在之前使用输入输出函数input()、print()
,我们就已经在调用函数了,这些是python自带的已经定义好的函数,而调用自己函数的方法和这些是一样的,只不过是在调用前必须先声明。
例如:调用上面第1个函数:
def hello(): #先声明
print('hello world')
hello() #再调用
#out: hello world
调用第2个函数:
def Sum(a, b): #先声明
s = 0
while a <= b:
s = s + a
a += 1
return s #有返回值
s = Sum(1,10) #再调用
print(s)
#out:55
注意:调用函数时,参数书写有两种方法
Sum(1, 10)
注意顺序不能颠倒,这种传参方法叫位置参数法;Sum(a=1, b=10)
或Sum(b=10, a=1)
,顺序可以颠倒,这种传参方法叫关键字参数法有的函数,在调用时你既可以传参数,也可以不传参数,例如,改写上面的 Sum
函数,不传入参数时默认计算1+…+100,传入参数时从多少开始到多少结束就从多少开始多少结束。
def Sum(a= 1, b= 100):
s = 0
while a <= b:
s = s + a
a += 1
return s
我们调用一下它:
... #这里是声明部分
s1 = Sum() #不传参数
s2 = Sum(10,1000) #传参数
print('s1= %d'%s1)
print('s2= %d'%s2)
#out:
s1= 5050
s2= 1501500
如果在声明函数时,参数中既有默认参数,也有普通参数,那么在声明时必须把默认参数放在普通参数后面,否则会报错,例如:
错误示例:
def test(a=3, b, c):
pass
SyntaxError: non-default argument follows default argument
正确示例:
def test(b,c,a=3):
pass
总之记住,默认参数放在普通参数后面
有一种情况,可能需要传入多个参数,但在定义时还不知到要声明多少个参数,此时在参数名前加上 *
则表示这是一个可变长参数
,如果在调用时,这个可变长参数前面的所有参数都已经被赋值后,还有多余的参数,那么这些多余的参数就会被收集在一个元组中,元组名就是带星号 *
的参数的参数名。
例如:
只有可变长参数
def test(*t):
print(t)
test(1)
test(1,2,3)
#out
(1,)
(1, 2, 3)
既有普通参数也有可变长参数,一般会把可变长参数放在最后面,例如
def test(a,b,*t):
pass
当然也可以把可变长参数放在前面,但在调用时就只能用关键字参数法来传递参数,否则后面的位置参数将因为无法获取值而发生错误。如:
错误传参法:
def test(*t,a):
print(t)
print(a)
test(1,2,3) #位置参数法传参,发生错误
TypeError: test() missing 1 required keyword-only argument: 'a'
正确传参法:
test(1,2,3,a=4)
#关键字参数传参,注意调用时a=4也不能调换顺序,如test(a=4,1,2,3)
#out:
(1, 2, 3)
4
所以,为了避免不必要的麻烦,最好在声明时把可变长参数放在最后面,不过这种声明在调用时不能使用关键字参数进行传参,只能用位置参数法
例如:
错误传参法:
def test(a,*t):
print(t)
print(a)
test(a=1,3,4,5) #关键字参数法
SyntaxError: positional argument follows keyword argument
正确传参法:
test(1,3,4,5)
#out:
(3, 4, 5)
1
好麻烦,看得头都大了,如果感到乱的听我一句话,记住第二种方法,很多时候我们更喜欢按顺序传入参数,简单又好看。>__<
用元组收集参数时,调用时提供的参数不能是关键字参数,如果要收集不定数量的关键字参数,可以在自定义的参数前加两颗星 **
,如 **valuename
这样一来,多余的关键字参数就会以字典的方式被存起来了,字典名就是 valuename
注意:声明和调用时关键字参数要放在最最最后面
例如:
def test(a,b=666,*t,**d):
print(a)
print(b)
print(t)
print(d)
test(1,2,3,4,5,c=10,d=11)
#out:
1
2
(3, 4, 5)
{
'c': 10, 'd': 11}
前面讨论的参数传递方法都是位置参数或关键字参数,实际上调用时还可以将元组和字典进行拆解调用
例如:
def test(a,b,c):
return a + b + c
t = (1,2,3)
d = {
'a':4,'b':5,'c':6} #键要与参数一一对应
print('拆解元组:',test(*t))
print('拆解字典:',test(**d))
#out:
拆解元组: 6
拆解字典: 15
python中元素有可变与不可变之分,像整数、浮点数、字符串、元组等都是不可变的,而列表、字典是可变的。
在函数调用时,若传入的参数是不可变参数,那么在函数内部对它的值修改时,在函数外部它的值是不变的,例如:
a = 1
def change(a):
a = 2
print('函数调用时a的值是%d'%a)
print('函数调用前a的值是%d'%a)
change(a)
print('函数调用后a的值是%d'%a)
#out:
函数调用前a的值是1
函数调用时a的值是2
函数调用后a的值是1
可见,虽然在函数内部a的值发生了改变,但是函数调用前后a的值一样
然而,如果在调用时传入的参数是可变的,那么在函数内部对它的值修改时,在函数外部它的值也会改变,例如:
b = [1,2]
def change(b):
b.append(3)
print('在函数调用时b是:',b)
print('在函数调用前b是:',b)
change(b)
print('在函数调用后b是:',b)
#out:
在函数调用前b是: [1, 2]
在函数调用时b是: [1, 2, 3]
在函数调用后b是: [1, 2, 3]
看,调用前后发生改变了吧!
列表,字典作为函数参数时的一个"陷阱":
def fun(L=[]):
L.append('abc')
print(L)
#三次调用这个函数
fun()
fun()
fun()
#看看输出结果:
['abc']
['abc', 'abc']
['abc', 'abc', 'abc']
哈哈,意外吧!所以说在调用函数时(不仅要注意顺序,而且)一定要注意传入参数的类型啊。
python中,作用域分以下几个:
每次运行函数,都会创建一个新的命名空间,这个新的命名空间就是局部作用域,同一函数在不同时间执行,其作用域是独立的(即互不影响);
不同函数作用域不同,可以有相同的参数名。
在函数内部声明过的变量,在函数外依然可以使用,并且在程序执行过程中,其值互不影响。(内外分明,互不影响)
看个例子:
def fun():
a = 1 #在函数内
print('局部',a)
a = 2 #在函数外
print('全局',a)
fun()
print('全局',a)
#out:
全局 2
局部 1
全局 2
然而,有一种方法可以在函数内部修改全局变量,就是在变量名前使用global
关键字
def fun():
global a #在函数内使用全局变量
a = 3
print('函数内',a)
a = 2 #在函数外
print('函数外',a)
fun()
print('函数外',a)
#out:
函数外 2
函数内 3
函数外 3
可以看到,在调用函数后函数外的变量 a 的值发生了变化。
lambda
可以用来创建匿名函数,也可以将匿名函数赋值给一个一个变量供调用,它是python中比较特殊的一种声明函数的方式,来源于 LISP 语言,其语法形式为:
lambda params:expression
params
:实际上就相当于函数的参数列表,中间有多个参数要用逗号 ,
隔开expression
:就相当于函数返回值的语句相当于没有函数名的一般函数,但一般函数必须要有函数名。
def <函数名>(params):
return expression
lambda
函数常在以下场景使用
例如:
z = lambda x,y:x ** 2 + y ** 2
z(3,4)
#out:
25
内建函数:指在python程序中没有导入任何模块或包就可以用的函数,除了之前用过的一些外,还有:
最后,提醒一点,filter()
和 map()
这两个函数比较重要,最好记住。