1函数简介
在程序中,如果发现某个功能的代码要多次使用,就把该代码块组织为一个模块,这一模块就是函数。我们可以举一个简单的例子进行说明:比如说,我们要计算圆的面积公式:S = ∏*r*r
r1 = 12.34
r2 = 9.08
r3 = 73.1
s1 = 3.14 * r1 * r1
s2 = 3.14 * r2 * r2
s3 = 3.14 * r3 * r3
所以有函数以后,我们就不需要写的那么麻烦只需要写一个函数进行调用即可。
2函数的定义和调用
函数定义如下:
def 函数名(): #括号里面的参数在后面的章节会重点讨论
代码(代码有缩进)
#定义函数,完成信息的打印功能
def printInfo():
print('***')
print('数据分析')
print('***')
定义函数后,相当于完成了某个功能的代码,想要代码执行,只需要调用即可。函数的调用如下:
printInfo()
****
数据分析
***
3函数的参数
在python中函数的定义非常简单,由于函数参数的存在,函数变的非常灵活,不但使得函数能够处理复杂多变的参数,而且还能简化参数的调用。Python中的函数参数有如下几种:位置参数 默认参数可变参数 关键字参数
3.1位置参数
计算x的平方的函数
def power(x):
return x * x
对于power(x)
函数,参数x就是一个位置参数,也叫必填参数。当我们调用power
函数时,必须传入有且仅有一个参数x:重新写入为:
def power(x):
return x *x
print(power(5))
25
如果要是计算x的三次方或者更高次方,可以另外定义:
def power(x,n):
while n > 0:
n = n - 1
s = s * x
return s
print(power(5,2))
print(power(5,3))
25
125
3.2默认参数
默认参数是指其中一个参数是固定的,我们并不需要全部输入,只需要输入其中的一个即可。但是默认参数一般放在函数参数的后面。
def power(x,n = 2):
s = 1
whlile n > 0:
n = n - 1
s = s * x
return s
25
25
使用默认参数可以简化书写
def enroll(name,gender):
print("name:",name)
print("gender:",gender)
这样我们设置好了一个函数,接下来我们需要调用函数:
enroll('Sarah','F')
name: Sarach
gender: F
如果想传入年龄城市等相关信息,需要继续调用函数,会显得较为复杂。因而我们会设定一些默认参数。
def enroll(name,gender,age = 6,city = 'Beijing'):
print('name:',name)
print('gender:',gender)
print('age:',age)
print('city:',city)
enroll('Sarah','F')
有了默认参数这个选项,我们就不需要再输入城市、年龄的相关信息了。
name: Sarch
gender: F
age: 6
city: beijing
只有与 默认参数信息 不符合的才需要重新输入:
enroll('Bob','M',7)
enroll('Adam','M',city = 'Tianjing')
name: Bob
gender: M
age: 7
city: beijing
name: Adma
gender: M
age: 6
city: Tianjing
默认有一个地方需要注意
def add_end(L=[]):
L.append('END')
return
print(add_end([1,2,3]))
print(add_end(['x','y','z']))
[1, 2, 3, 'END']
['x', 'y', 'z', 'END']
但是如果使用默认参数调用时,一开始结果是对的,但是再次调用的时候就出现了错误。
def add_end(L= []):
L.append('END')
return L
print(add_end())
print(add_end())
print(add_end())
['END']
['END', 'END']
['END', 'END', 'END']
python函数在定义的时候,默认参数L
的值被计算出来了,即[]
,默认参数L
也是一个变量,它指向对象[],每次调用该函数,如果改变了L
的内容,下次调用的时候,默认参数的内容就变了,不再是函数定义的[]
了。所以定义默认参数要牢记一点:默认参数必须指向不变对象!所以我们修改上面的例子
def add_end(L = None):
if L is None:
L = []
L.append('END')
return
['END']
['END']
['END']
不变对象一旦创建,对象内部的数据就不能修改,这样就减少了由于修改数据导致的错误。此外,由于对象不变,多任务环境下同时读取对象不需要加锁,因此同时读取不会出现问题。
3.3可变参数
可变参数顾名思义就是定义的参数是可变的,可变参数就是传入的参数个数是可变的 可以是1个、2个到任意个,还可以是0个。如果我们要计算a的平方一直加到无穷,所以我们需要确定输入的参数,由于参数个数不确定,所以我们可以将a,b,c...作为一个list
tuple
传进来,我们可以定义函数如下:
def calc(numbers):
sum = 0
for n in numbers:
sum = sum + n * n
return sum
print(calc[1,2,3])
14
如果是利用可变参数那么问题就会简单很多,
calc(1,2,3)
calc(1,3,5,7)
将函数调成可变参数如下:
def calc(*numbers):
sum = 0
for n in numbers:
sum = sum + n * n
return sum
print(calc(1,2,3))
print(calc(1,3,5))
14
35
如果已经有了一个list
或者tuple
,需要调用可变参数就只需要在调用的地方添加即可。例如:
num = [1,2,3]
calc(*num)
14
3.4 命名关键字参数
对于关键字参数,函数的调用者可以传入任意不受限制的关键字参数。至于传入哪些,就需要在函数内部通过kw
检查
我们以person
为例:
def person(name,age,**kw):
if 'city' in kw:
pass
if 'job' in kw:
pass
print('name:',name,'age:',age,'other:',kw)
person('jack',24,city = 'Beijing',addr = 'chaoyang',zipcode = 123456)
输出结果为:
name: jack age: 24 other: {'city': 'Beijing', 'addr': 'chaoyang', 'zipcode': 123456}
所以我们可以看出,后面不在的参数例如city
addr
zipcode
都用字典的形式展现出来。
3.5 参数组合
在参数中,可以用必选参数,默认参数,可变参数,关键字参数和命名关键字参数进行组合,而且命令的顺序也是如此:
def f1(a,b,c=0,*args,**kw):
print('a =' ,a, 'b =',b,'c=',c,'args=',args,'kw=',kw)
def f2(a,b,c=0,*,d,**kw):
print('a =',a,'b=',b,'c=',c,'d=',d,'kw=',kw)
f1(1,2)
f1(1,2,c=3)
f1(1,2,3,'a','b')
f1(1,2,3,'a','b',x=99)
f2(1,2,d=99,ext= None)
a = 1 b = 2 c = 0 args = () kw = {}
a = 1 b = 2 c = 3 args = () kw = {}
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {}
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99}
a = 1 b= 2 c= 0 d= 99 kw= {'ext': None}
在使用函数的时候,尽量不要使用太多的混合参数,否则函数的理解性很差。
3.6 递归函数
在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,就这个就是递归函数。我们用fact(n)
,其中fact(n) = n! = 1 * 2 * 3 * 4 * 5 * 6 * (n-1) * n
def fact(n):
if n == 1:
return 1
return n * fact(n - 1)
fact(1)
fact(5)
1
120
4 函数的返回值
4.1 函数的返回值介绍
所谓的"返回值",就是程序中函数完成一件事情后,最后调用者的结果。举例如下:
def cal(a,b):
c = a +b
return c #返回值
print(cal(1,2))
3
def cal(a,b):
return a + b
print(cal(1,5))
6
我们发现打印print(cal(1,5))
会很琐碎,因而可以使用另外一种保存函数的方法:
def cal(a,b):
return a + b
result = cal(100,98)
print(result)
198
return
函数还有另外一个作用,就是结束函数,我们来看来两个例子:
def cal_nums():
print("--1---")
return 1
print("----2---")
return 2
print("----3----")
cal_nums()
--1---
return
的功能就是结束运算,后面的就不需要执行了。一个函数也会返回多个数据的方式
def calculate(a,b):
shang = a // b
yushu = a % b
return shang,yushu #默认元组
result = calculate(5,2)
print(result)
def calculate(a,b):
shang = a // b
yushu = a % b
return shang,yushu #返回的是元组
result = calculate(5,2)
print(result)
(2,1)
6局部变量与全局变量
6.1局部变量
就是在函数内部定义的变量,作用是只能在函数内部使用,在函数的外部是不能使用的。为了临时保存数据需要在函数中定义变量来进行储存。当函数调用时,局部变量被创建,当函数调用完成后这个变量就不能够使用了。
def show():
#定义局部变量
sal = 15000
print("薪资:",sal)
show()
薪资: 15000
6.2全局变量
如果一个变量,既能在一个函数中使用,也能在其他的函数中使用,这样的变量就是全局变量。例如:有2个兄弟都有手机,各自有自己的小秘密在手机里,不让另外一方使用(可以理解为局部变量) 如果家里的电话是2个兄弟都可以随便使用的(可以理解为全局变量) 举一个例子:
money = 1200
def test1():
print(money)
def test2():
print(money)
#调用函数
test1()
test2()
总结:
在函数外定义的变量叫做全局变量 全局变量能够在所有的函数中进行访问
6.3全局变量与局部变量冲突问题
#定义全局变量
x = 1000
def test1():
#定义局部变量,与全局变量名字相同
x = 300
print('----test1----%d'%x)
#修改
x = 200
print('x = %d'%x)
test1()
test2()
6.4修改全局变量
x = 100
def test1():
#定义全局变量
global x
print('修改之前:%d'%x)
#修改
x = 200
print('修改后%d'%x)
def test2():
print('x = %d'%x)
test1()
test2()
修改之前:100
修改后200
x = 200
7 捕获异常
一旦出错,还要一级一级上报,知道某个函数可以理解该错误。所以高级语言都内置了一套try...except...finally
的错误处理机制。python 也不例外,我们来看一个简单的例子。
try:
print('try....')
r = 10 / 0
except ZeroDivisionError as e:
print('except:',e)
finally:
print('finally...')
print('END')
当我们认为代码可能会出错时,使用try
运行这段代码,如果执行错误,后续代码
不会继续执行,就会直接跳转到except
代码块。执行完except
后如果有 finally
就会执行finally
try...
except: division by zero
finally...
END
同样,如果我们把上式中的0
修改为2
,我们继续执行就会出现如下结果:
try...
result: 5.0
finally...
END
说明在异常部分没有执行,但是仍然继续执行下面的代码。
在真实的编程过程中,会有很多种类的错误,如果发生了不同类型的错误,就应该由不同的except
语块处理。就应该由duogeexpect
来捕获不同类型的错误。再举一个例子:
try:
print('try...')
r = 10 / int('a')
print('result:',r)
except ValueError as e:
print('ValueError:',e)
except ZeroDivisionError as e:
print('ZeroDivisionError:',e)
finally:
print('finally....')
print('END')
输出结果为:
try...
ValueError: invalid literal for int() with base 10: 'a'
finally....
END
因为int()
函数可能会抛出valueError
,所以我们用except
捕获valueError
,用另外一个except
捕获zeroDivisionError
此外我们可以在except
语块后面加一个else
,所以当没有错误发生时,会自动执行else
语句:
try:
print('try...')
r =10/int('2')
print('result:',r)
except ValueError as e:
print('ValueError:',e)
except ZeroDivisionError as e:
print('ZeroDivisionError:',e)
else:
print("no error!")
finally:
print('finally...')
print('END')
try...
result: 5.0
no error!
finally...
END
Python的错误其实也是class
,所有的错误类型都继承自BaseExcept
,所以在使用except
时需要注意的是,它不但捕获该类型的错误,还能把其他子类也一并处理。
try:
foo()
except ValueError as e:
print('ValueError')
except UnicodeError as e:
print('UnicodeError')
第二个except
永远也捕捉不到unicodeError
。python的常见错误是从BaseException
类派生出来的。常见的错误类型和继承关系可以参看
使用try...except
捕获错误还有一个巨大的好处,就是可以跨越多层调用,比如main()
调用foo()foo()
调用bar()
结果bar()
这时,只要main()
捕捉到了就可以处理。
def foo(s):
return 10 /int(s)
def bar(s):
return foo(s) * 2
def main():
try:
bar('0')
except Exception as e:
print('Error:',e)
finally:
print('finally...')
不需要在每个可能出错的地方去捕捉错误,只要在合适的层次去捕获错误就可以了。这样一来就大大减少了try...except...finally
的麻烦。




