Python初学小知识(九):函数
C语言和Python经常弄混,尤其总是忍不住给Python后面加分号……干脆给自己做个笔记省的忘了。。。(在慕课网学习的)
十三、函数
1. 简介
使用函数,把重复的逻辑代码封装起来,我们把封装重复逻辑代码的过程就做抽象,抽象是数学中非常常见的概念。在这个文档里面,列举了Python内置的大部分函数。
传递的参数数量、类型一定要和函数要求的一致,不然将会引起错误。
sum()函数接收一个list作为参数,并返回list所有元素之和。请计算 1×1 + 2×2 + 3×3 + … + 100×100。
L = []
x = 1
while x <= 100:
L.append(x * x)
x = x + 1
print(sum(L))
>>> 338350
2. 定义函数
2.1 def()
定义一个函数要使用 def 语句,依次写出函数名、括号()、括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用 return 语句返回。
#定义一个求绝对值的函数
def my_abs(x):
if x >= 0:
return x
else:
return -x
my_abs(-3)
>>> 3
2.2 return()
2.2.1 返回一个值
return表示返回的意思,函数体内部的语句在执行时,一旦执行到return时,函数就执行完毕,并将结果返回。
#定义一个求列表list所有元素的和的函数
def list_sum(L):
result = 0
for num in L:
result = result + num
return result
2.2.2 返回None
如果在函数内把结果打印出来,不通过return返回结果:
#定义一个求列表list所有元素的和的函数
def list_sum(L):
result = 0
for num in L:
result = result + num
print('result is {}'.format(result))
return
L = [1, 3, 5, 7, 9, 11]
result =list_sum(L) #调用定义的sum_list函数并获得return返回的结果
print(result)
>>> result is 36
None
在print(result)中,我们得到None的结果,这是合理的,因为在函数内部,我们把结果打印出来了,但是没有把结果返回。
2.2.2 返回多个值
函数也可以返回多个值,多个值之间使用逗号分隔即可,但是需要注意顺序。
def data_of_square(side):
C = 4 * side
S = side * side
return C, S
C, S = data_of_square(16)
print('周长 = {}'.format(C)) # ==> 周长 = 64
print('面积 = {}'.format(S)) # ==> 面积 = 256
#也可以使用一个值存储函数返回的多值结果:
result = data_of_square(16)
print(result) # ==> (64, 256)
#打印的result,其实是tuple类型,如果我们需要取出结果中的周长或者面积,使用对应位置的下标即可:
print(result[0]) # ==> 64
print(result[1]) # ==> 256
3. 递归函数
在函数内部,还可以调用其他函数,通过合理拆分逻辑,可以降低程序的复杂度。如果在一个函数内部调用其自身,这个函数就是递归函数。
计算阶乘 n! = 1 * 2 * 3 * … * n
'''可以看出:fact(n) = n! = 1 * 2 * 3 * ... * (n-1) * n = (n-1)! * n = fact(n-1) * n
所以,fact(n)可以表示为 n * fact(n-1),只有n=1时需要特殊处理。'''
def fact(n):
if n == 1:
return 1
return n * fact(n - 1)
print(fact(1)) # ==> 1
print(fact(5)) # ==> 120
我们可以拆解fact(5)计算的详细逻辑:
===> fact(5)
===> 5 * fact(4)
===> 5 * (4 * fact(3))
===> 5 * (4 * (3 * fact(2)))
===> 5 * (4 * (3 * (2 * fact(1))))
===> 5 * (4 * (3 * (2 * 1)))
===> 5 * (4 * (3 * 2))
===> 5 * (4 * 6)
===> 5 * 24
===> 120
递归函数的优点是定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。
使用递归函数需要注意防止栈溢出:
>>> print(fact(10000))
Traceback (most recent call last):
File "index.py", line 8, in
print(fact(10000))
File "index.py", line 6, in fact
return n * fact(n-1)
File "index.py", line 6, in fact
return n * fact(n-1)
File "index.py", line 6, in fact
return n * fact(n-1)
File "index.py", line 6, in fact
return n * fact(n-1)
File "index.py", line 6, in fact
return n * fact(n-1)
......
4. 函数使用参数
函数参数可以是任意的数据类型,只要函数内部逻辑可以处理即可。
isinstance()函数可以判断参数类型,它接收两个参数,第一个是需要判断的参数,第二个是类型。
>>> isinstance('abcd', str)
True
>>> isinstance(100.0, int)
False
>>> isinstance((1,2), tuple)
True
>>> isinstance({'A':1, 'B':2}, dict)
True
>>> isinstance([1,2], str)
False
>>> isinstance([1,2], list)
True
利用isinstance()函数可以优化函数,比如:
def my_abs(x):
if not isinstance(x, int) or not isinstance(x, float):
print('param type error.')
return None
if x >= 0:
return x
else:
return -x
5. 函数使用默认参数
默认参数的意思是当这个参数没有传递的时候,参数就使用定义时的默认值。
例如Python自带的 int() 函数,其实就有两个参数,我们既可以传一个参数,又可以传两个参数:
#int(value, [base=10]),base表示value的进制,int()返回十进制
>>> int('12') #默认base=10
12
>>> int('12', 8) #12是八进制,返回十进制是10
10
>>> int('12', 16)
18
函数的默认参数的作用是简化调用,我们只需要把必须的参数传进去。但是在需要的时候,又可以传入额外的参数来覆盖默认参数值:
#定义一个计算 x 的N次方的函数:
def power(x, n):
s = 1
while n > 0:
n = n - 1
s = s * x # n=1,2时满足while条件,所以s乘了两次x
return s
print(power(5, 2)) # ==> 25
假设计算平方的次数最多,我们就可以把 n 的默认值设定为 2:
def power(x, n=2):
s = 1
while n > 0:
n = n - 1
s = s * x
return s
power(5) # ==> 25
由于函数的参数按从左到右的顺序匹配,所以默认参数只能定义在必需参数的后面,否则将会出现错误,如:def power(n=2, x)
6. 函数使用可变参数
Python函数还接收一种参数叫做可变参数,可变参数即任意个参数的意思,可变参数通常使用*args来表示:
def func(*args):
print('args length = {}, args = {}'.format(len(args), args))
func('a')
func('a', 'b')
func('a', 'b', 'c')
#结果:
args length = 1, args = ('a',)
args length = 2, args = ('a', 'b')
args length = 3, args = ('a', 'b', 'c')
Python会把可变参数定义为一个tuple,所以在函数内部,可以把可变参数当作tuple来使用。
定义可变参数的目的也是为了简化调用。假设我们要计算任意个数的平均值,就可以定义一个可变参数:
def average(*args):
sum = 0
for item in args:
sum += item
return sum / len(args)
print(average(1,2,3,4)) # ⇒ 2.5
7. 函数使用可变关键字参数
Python的参数是看作元组的,只能通过索引去寻找,如果顺序发生变化得时候,下标就会失效,函数逻辑就得重新修改实现。
与字典类似,Python函数提供可变关键字参数,可以通过关键字的名字key找到对应的参数值。
def info(**kwargs):
print('name: {}, gender: {}, age: {}'.format(kwargs.get('name'), kwargs.get('gender'), kwargs.get('age')))
info(name = 'Alice', gender = 'girl', age = 16)
#结果是:name: Alice, gender: girl, age: 16
对于一个拥有必需参数,默认参数,可变参数,可变关键字参数的函数,定义顺序是这样的:
def func(param1, param2, param3 = None, *args, **kwargs):
print(param1)
print(param2)
print(param3)
print(args)
print(kwargs)
func(100, 200, 300, 400, 500, name = 'Alice', score = 100)
# ==> 100
# ==> 200
# ==> 300
# ==> (400, 500)
# ==> {'name': 'Alice', 'score': 100}
编写一个函数,它接受关键字参数names,gender,age三个list,分别包含同学的名字、性别和年龄,请分别把每个同学的名字、性别和年龄打印出来。
def info(**kwargs):
names = kwargs['names']
gender_list = kwargs['gender']
age_list = kwargs['age']
index = 0
for name in names:
gender = gender_list[index]
age = age_list[index]
print('name: {}, gender: {}, age: {}'.format(name, gender, age))
index += 1
info(names = ['Alice', 'Bob', 'Candy'], gender = ['girl', 'boy', 'girl'], age = [16, 17, 15])
#结果是:
name: Alice, gender: girl, age: 16
name: Bob, gender: boy, age: 17
name: Candy, gender: girl, age: 15