python学习之--⾃定义函数:
Python之--⾃定义函数:
在Python中,定义⼀个函数要使⽤def语句,依次写出函数名、括号、括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值⽤return语句返回。
以下⾃定义⼀个函数⽤于判断⼀个⼈是成年⼈好事青少年:
1 >>> def judge_person(age):
2 ... if age < 18:
3 ... print("teenager!")
4 ... else:
5 ... print("adult!")
6 ...
7 >>> judge_person(12)
8 teenager!
9 >>> judge_person(23)
10 adult!
11 >>>
请注意,函数体内部的语句在执⾏时,⼀旦执⾏到return时,函数就执⾏完毕,并将结果返回。因此,函数内部通过条件判断和循环可以实现⾮常复杂的逻辑。
如果没有return语句,函数执⾏完毕后也会返回结果,只是结果为None。
return None可以简写为return
1 >>> def get_age(age):
2 ... if age > 18:
3 ... return"older"
4 ... else:
5 ... return
6 ...
7 >>> get_age(12)
8 >>> get_age(56)
9'older'
10 >>>
空函数:
什么叫做”空函数“?所谓的空函数就是你定义⼀个函数,但是什么也不⽤做,就是定义了⼀个空函数!例如:
1 >>> def Empty():
2 ... pass
3 ...
4 >>> def Empty2():
5 ... pass
6 ...
7 >>>
pass语句什么都不做,那有什么⽤?实际上pass可以⽤来作为占位符,⽐如现在还没想好怎么写函数的代码,就可以先放⼀个pass,让代码能运⾏起来。
pass还可以⽤在其他语句⾥,⽐如:
1 >>> age = 90
2 >>> if age:
3 ... pass
4 ...
5 >>> #如果没有pass就会报错。
6 ...
7 >>> if age:
8 ...
9 File "<stdin>", line 2
10
11 ^
12 IndentationError: expected an indented block
13 >>>
调⽤函数时,如果参数个数不对,Python解释器会⾃动检查出来,并抛出TypeError:
但是如果参数类型不对,Python解释器就⽆法帮我们检查。
当传⼊了不恰当的参数时,内置函数abs会检查出参数错误,⽽我们定义没有参数检查,所以,这个函数定义不够完善。
以下定义⼀个求绝对值的函数:
1 >>> def get_abs(value):
2 ... if value < 0:
3 ... return -value
4 ... else:
5 ... return value
6
7 >>> get_abs(2)
8 2
9 >>> get_abs(-3)
10 3
11 >>> get_abs(0)
12 0
13 >>>
让我们修改⼀下我们函数定义get_abs,对参数类型做检查,只允许整数和浮点数类型的参数。数据类型检查可以⽤内置函数isinstance实现:
1 >>> get_abs(dada)
2 Traceback (most recent call last):
3 File "<stdin>", line 1, in <module>
4 NameError: name 'dada'is not defined
5 >>> #在没有进⾏参数检查之前,报出了⼀个NameError:的错误
6 ... #以下我们对函数进⾏参数检查,提⾼函数的健壮性。
7 ...
8 >>> def get_abc(value):
9 ... if not isinstance(value,(int,float)):
10 ... raise TypeError('参数类型不对,不好意思啊!')
11 ... if value >= 0:
12 ... return value
13 ... else:
14 ... return -value
15 ...
16 >>> #传⼊正确的参数:
17 ...
18 >>> get_abc(12)
19 12
20 >>> get_abc(-12)
21 12
22 >>> #传⼊错误的参数:
23 >>> get_abc('gn')
24 Traceback (most recent call last):
25 File "<stdin>", line 1, in <module>
26 File "<stdin>", line 3, in get_abc
27 TypeError: 参数类型不对,不好意思啊!
28 >>>
返回多个值:
⽐如在游戏中经常需要从⼀个点移动到另⼀个点,给出坐标、位移和⾓度,就可以计算出新的新的坐标:
1import math
2
3def move(x, y, step, angle=0):
4 nx = x + step * s(angle)
5 ny = y - step * math.sin(angle)
6return nx, ny
例⼦:
1 >>> import math
2 >>>
3 >>> def move(x,y,step,angle = 0):
4 ... nx = x + s(angle)
5 ... ny = y - step*math.sin(angle)
6 ... return nx,ny
7 ...
8 >>> x1,y1 = move(100,10,60,math.pi/6)
9 >>> print x1,y1
10 151.961524227 -20.0
11 >>>
其实,返回的值是⼀个元组(tuple)。
函数的参数:
定义函数的时候,我们把参数的名字和位置确定下来,函数的接⼝定义就完成了。对于函数的调⽤者
来说,只需要知道如何传递正确的参数,以及函数将返回什么样的值就够了,函数内部的复杂逻辑被封装起来,调⽤者⽆需了解。
Python的函数定义⾮常简单,但灵活度却⾮常⼤。除了正常定义的必选参数外,还可以使⽤默认参数、可变参数和关键字参数,使得函数定义出来的接⼝,不但能处理复杂的参数,还可以简化调⽤者的代码。
1.默认参数:
定义⼀个计算平⽅的函数:power()
1 >>> def power(x):
2 ... return x*x
3 ...
4 >>> power(5)
5 25
6 >>> power(7)
7 49
8 >>>
当我们调⽤power函数时,必须传⼊有且仅有的⼀个参数x.但是此时我们要定义⼀个计算x的三次⽅甚⾄更多的次⽅该怎么办呢,或许聪明的读者已经想到了
把power(x)修改为:power(x,n)实例如下:
1 >>> def power(x,n):
2 ... s = 1
3 ... while n > 0:
4 ... n = n-1
5 ... s = s * x
6 ... print s
7 ...
8 >>> power(2,2)
9 4
10 >>> power(2,9)
11 512
12 >>> #但是此时想要使⽤power(x)求x的平⽅的话,该⽅法已经没有效果了。
13 ...
14 >>> power(5)
15 Traceback (most recent call last):
python新手函数16 File "<stdin>", line 1, in <module>
17 TypeError: power() takes exactly 2 arguments (1 given)
18 >>> #此处我们可以引⼊默认参数来解决这个问题:
19 ...
20 >>> def power(x,n = 2):
21 ... s = 1
22 ... while n > 0:
23 ... n -= 1
24 ... s *= x
25 ... print s
26 ...
27 >>> power(5,2)
28 25
29 >>> power(5)
30 25
31 >>> #这样就可以实现效果了!是不是很帅!
⽽对于n > 2的其他情况,就必须明确地传⼊n,⽐如power(5, 3)。
从上⾯的例⼦可以看出,默认参数可以简化函数的调⽤。设置默认参数时,有⼏点要注意:
⼀是必选参数在前,默认参数在后,否则Python的解释器会报错(思考⼀下为什么默认参数不能放在必选参数前⾯);
⼆是如何设置默认参数。
当函数有多个参数时,把变化⼤的参数放前⾯,变化⼩的参数放后⾯。变化⼩的参数就可以作为默认参数。
使⽤默认参数有什么好处?最⼤的好处是能降低调⽤函数的难度。
可见,默认参数降低了函数调⽤的难度,⽽⼀旦需要更复杂的调⽤时,⼜可以传递更多的参数来实现。
⽆论是简单调⽤还是复杂调⽤,函数只需要定义⼀个。
默认参数虽然可以带来很⼤的便利,但是也有⼀个相当⼤的弊端:
先定义⼀个函数,传⼊⼀个list,添加⼀个END再返回:
1 >>> def add_end(L=[]):
2 ... L.append(['END'])
3 ... return L
4 ...
5 >>> add_end([1,2,3])
6 [1, 2, 3, ['END']]
7 >>> add_end(['x','y','z'])
8 ['x', 'y', 'z', ['END']]
9 >>> #当你使⽤默认参数的时候,刚开始是对的:
10 ...
11 >>> add_end()
12 [['END']]
13 >>> #但是再次调⽤add_end()时,结果就不对了
14 ...
15 >>> add_end()
16 [['END'], ['END']]
17 >>> add_end()
18 [['END'], ['END'], ['END']]
19 >>>
默认参数是[],但是函数似乎每次都“记住了”上次添加了'END'后的list。这是为什么呢?
Python函数在定义的时候,默认参数L的值就被计算出来了,即[],因为默认参数L也是⼀个变量,它指向对象[],每次调⽤该函数,如果改变了L的内容,则下次调⽤时,默认参数的内容就变了,不再是函数定义时的[]了。
所以,定义默认参数要牢记⼀点:默认参数必须指向不变对象!
要修改上⾯的例⼦,我们可以⽤None这个不变对象来实现:
1 >>> def add_end(L = None):
2 ... if L is None:
3 ... L = []
4 ... L.append('END')
5 ... return L
6 ...
7 >>> #演⽰:
8 ...
9 >>> add_end()
10 ['END']
11 >>> add_end()
12 ['END']
13 >>> add_end()
14 ['END']
15 >>>
为什么要设计str、None这样的不变对象呢?因为不变对象⼀旦创建,对象内部的数据就不能修改,这样就减少了由于修改数据导致的错误。此外,由于对象不变,多任务环境下同时读取对象不需要加锁,同时读⼀点问题都没有。我们在编写程序时,如果可以设计⼀个不变对象,那就尽量设计成不变
对象。
2. 可变参数:
在Python函数中可以传⼊默认参数,但是也可以传⼊可变参数.不难理解,可变参数的含义就是说,参数的个数时可以改变的,可以是1个、2个到任意个,还可以是0个。
我们以数学题为例⼦,给定⼀组数字a,b,c……,请计算a2 + b2 + c2 + ……。
要定义出这个函数,我们必须确定输⼊的参数。由于参数个数不确定,我们⾸先想到可以把a,b,c……作为⼀个list或tuple传进来,这样,函数可以定义如下:
在没有使⽤可变参数的情况:
1 >>> def get_value(numbers):
2 ... sum = 0
3 ... for n in numbers:
4 ... sum += n * n
5 ... return sum
6 ...
7 >>> #但是调⽤的时候要先拼接⼀个元组或者列表
8 ...
9 >>> get_value([1,2,3,4,5,6,7,8,9,10])
10 385
11 >>> get_value((1,2,3,3,4,5,6))
12 100
使⽤可变参数,把函数修改为如下:
1 >>> def get_value(*numbers):
2 ... sum = 0
3 ... for n in numbers:
4 ... sum += n*n
5 ... return sum
6 ...
7 >>> get_value(1,2,3,4,5,6)
8 91
定义可变参数和定义list或tuple参数相⽐,仅仅在参数前⾯加了⼀个*号。在函数内部,参数numbers接收到的是⼀个tuple,因此,函数代码完
全不变。但是,调⽤该函数时,可以传⼊任意个参数,包括0个参数:
1 >>> get_value(1)
2 1
3 >>> get_value(0)
4 0
但是,当你传⼊⼀个列表或者元组会出现错误:
1 >>> get_value([1,2,3,4,5,6])
2 Traceback (most recent call last):
3 File "<stdin>", line 1, in <module>
4 File "<stdin>", line 4, in get_value
5 TypeError: can't multiply sequence by non-int of type 'list'
6 >>> get_value((1,2,3,4,5,6))
7 Traceback (most recent call last):
8 File "<stdin>", line 1, in <module>
9 File "<stdin>", line 4, in get_value
10 TypeError: can't multiply sequence by non-int of type 'tuple'
11 >>>
可以这样解决列表和元组的问题:
1 >>> list1 = [8,9]
2 >>> tuple1 = (1,2,3)
3 >>> list1
4 [8, 9]
5 >>> tuple1
6 (1, 2, 3)
7 >>> get_value(list1[0],list1[1])
8 145
9 >>> get_value(tuple1[0],tuple1[1],tuple1[2])
10 14
11 >>>
但是,这种⽅法不是最好的,假如元组或者列表很⼤的时候就会出现⼯作量的问题,因此有⼀个更好的办法就是:Python允许你在list或tuple前⾯加⼀个*号,把list或tuple的元素变成可变参数传进去:
1 >>> list1
2 [8, 9]
3 >>> tuple1
4 (1, 2, 3)
5 >>> get_value(*tuple1)
6 14
7 >>> get_value(*list1)
8 145
9 >>>
有⽊有感觉python真的是⽆可挑剔啊,确实是这样的。
3. 关键字参数:
可变参数允许你传⼊0个或任意个参数,这些可变参数在函数调⽤时⾃动组装为⼀个tuple。⽽关键字参数允许你传⼊0个或任意个含参数名的参数,这些关键字参数在函数内部⾃动组装为⼀个dict。请看⽰例:
1 >>> def person(name,age,**kw):
2 ... print'name:',name,'age:',age,'other:',kw
3 ...
4 >>> #函数person除了必选参数name和age外,还接受关键字参数kw。在调⽤该函数时,可以只传⼊必选参数:
5 ...
6 >>> person('lt',20)
7 name: lt age: 20 other: {}
8 >>>
也可以传⼊任意个关键字参数:
1 >>> person('lt',20,city = 'shanghai',height = 178,love = 'lt')
2 name: lt age: 20 other: {'city': 'shanghai', 'love': 'lt', 'height': 178}
3 >>> person('lt',20,city = 'shanghai',height = 178,love = 'lt',salary = 200000)
4 name: lt age: 20 other: {'salary': 200000, 'city': 'shanghai', 'love': 'lt', 'height': 178}
5 >>>
关键字参数有什么⽤?它可以扩展函数的功能。⽐如,在person函数⾥,我们保证能接收到name和ag
e这两个参数,但是,如果调⽤者愿意提供更多的参数,我们也能收到。试想你正在做⼀个⽤户注册的功能,除了⽤户名和年龄是必填项外,其他都是可选项,利⽤关键字参数来定义这个函数就能满⾜注册的需求。
和可变参数类似,也可以先组装出⼀个dict,然后,把该dict转换为关键字参数传进去:
1 >>> kw = {'name':'lt','city':'shanghai','hometown':'xinnong','age':20}
2 >>> kw
3 {'city': 'shanghai', 'age': 20, 'name': 'lt', 'hometown': 'xinnong'}
4 >>> person('jack',20,city=kw['city'],hometown = kw['hometown'])
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论