1. 调用函数
(1)Python有很多内置的函数,可以直接调用
(2)调用一个函数,需要知道函数的名称和参数
(3) 查看具体函数信息:
查看 绝对值函数:abs()
http://docs.python.org/3/library/functions.html
或者:
help(abs) 可以得到一些相关信息
(4) 调用函数时的报错信息
a. TypeError : 传入的参数数量不对 或者 参 数的参数类型错误
示例:abs(1,2)
2. 数据类型转换
(1)对数据处理必须明确数据的类型才能运算处理。
示例:
int('123')
int(12.34)
float('12.34')
str(1.23)
bool(1)
(2) 给函数起一个别名
>>> a =abs # 变量a指向abs函数
>>> a(-1) #所以也可以通过a调用abs函数
3. 定义函数
(1) 定义函数的语句: def 语句
示例:
def my_abs(x):
if x>=0 :
return x
else:
return -x
(2) 如何使用自己定义的函数
示例:
my_abs()保存成一个名为abtest.py文件
from abstest import my_abs
(3) 定义一个空函数:(会用到pass语句)
def nop():
pass
注释: pass语句什么都不做,一般用来在构建一个函数的逻辑思路前用来占位。
if age>=18:
pass
(4)Pythong解释器对函数的参数检查
a. 参数个数不对,Python解释器会报出TypeError的错误。
b. 参数类型不对,Python解释器的报错信息不会解释具体出错信息。
c. 如何在自己定义的函数里设置参数检查:
def my_abs(x):
if not isinstance(x,(int,float)):
raise TypeError('bad operand type')
if x>=0 :
return x
else:
return -x
(5) 在函数中返回多个值:
适用范围:坐标等
示例:
import math
def move(x,y,step,angle=0):
nx=x+step*math.cos(angle)
ny=y-step*math.sin(angle)
return nx,ny
x,y=move(100,100,60,math.pi/6)
print(x,y)
注意:看似返回的是多个值,实际上返回的是一个tuple类型数据。
r=move(100,100,60,math.pi/6)
print(r)
(6) return 语句
函数执行完毕时,没有return语句的,自动增加一条语句:return None
4. 函数的参数
(1) 定义函数的时候,我们把参数的名字和位置确定下来,函数的接口定义就完成了。
对于函数的调用者来说,只需要知道如何传递正确的参数,以及函数将返回什么样的值就够了,函数内部的复杂逻辑被封装起来,调用者无需了解。
(2)Python的参数有(参数的多样化,可以处理更复杂的参数):
必选参数,默认参数,可变参数,关键字参数。
(3)位置参数:
def power(x):
return x*x
位置参数是在调用函数时,传入的两个值按照位置顺序依次赋给参数x和n。
(4)默认参数
对参数设置默认值,在传参时可以缺省该参数。
def power(x,n=2):
s=1
while n>0:
n=n-1
s=s*x
return s
power(5)
power(5,2)
注意:
Python中 必选参数在前,默认参数在后,否则Python的解释器会报错。
定义默认参数时,必须指向不变对象(比如常量),如果指向变化对象(比如集合)容易出现程序bug
测试:
def add_end(L=[]):
L.append('END')
return L
add_end([1,2,3])
add_end(['x','y','z'])
add_end()
add_end()
合理写法:(检查默认参数所指向的可变对象是否符合要求)
def add_end(L=None):
if L is None:
L = []
L.append('END')
return L
(5) 可变参数
可变参数就是传入的参数个数是可以变化的。
def calc(*numbers):
sum=0
for n in numbers:
sum=sum+n*n
return sum
参数在函数内部是一个tuple(元组)
calc(1,2)
将一个元组用可变参数的方式传入函数内部:
nums=[1,2,3]
calc(*nums)
(6) 关键字参数
关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict
def person(name,age,**kw):
print('name:',name,'age:',age,'other',kw)
person('Michael',30)
person('Bob',35,city='beijing')
person('Adam',45,gender='M',job='Engineer')
关键字参数的适用场景举例:
在一个用户注册页面,由必选项目(必选参数)和可选项目(关键字参数)来完成用户注册的需要
(7)命名关键字参数
关键字参数可以传入任意不受限制的参数,而命名关键字参数则会要求只传递特定的关键字参数
示例:
不加限制前,在函数内部检查是否有我们要的关键字参数
def person(name,age,**kw):
if 'city' in kw:
pass
if 'job' in ke:
pass
print('name',name,'age',age,'other',kw)
通过命名关键字参数,我们可以在传递参数时就对参数进行限制
ded person(name,age,*,city,job):
print(name,age,city,job)
和关键字参数**kw不同,命名关键字参数需要一个特殊分隔符 *,* 后面的参数视为命名关键字参数
person('Jack',24,city='Beijing',job='Engineer')
如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了
def person(name,age,*args,city,job):
print(name,age,args,city,job)
注意:命名关键字参数必须传入参数名,这个位置参数不同,如果没有传入参数名,调用将报错
6. 参数组合
5种参数可以组合使用,参数定义的顺序必须是:
必选参数,默认参数,可变参数,命名关键字参数和关键字参数
def f1(a,b,c=0,*args,**kw):
print('a=',a,'b=',b,'c=','args=',args,'kw=',kw)
def f2(a,b,c=0,*,d,**kw):
print('a=',a,'b=',b,'c=',c,'d=',d,'kw=',kw)
在函数调用的时候,Python解释器自动按照参数位置和参数名把对应的参数传进去。
>>> f1(1, 2)
a = 1 b = 2 c = 0 args = () kw = {}
>>> f1(1, 2, c=3)
a = 1 b = 2 c = 3 args = () kw = {}
>>> f1(1, 2, 3, 'a', 'b')
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {}
>>> f1(1, 2, 3, 'a', 'b', x=99)
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99}
>>> f2(1, 2, d=99, ext=None)
a = 1 b = 2 c = 0 d = 99 kw = {'ext': None}
最神奇的是通过一个tuple和dict,你也可以调用上述函数:
>>> args = (1, 2, 3, 4)
>>> kw = {'d': 99, 'x': '#'}
>>> f1(*args, **kw)
a = 1 b = 2 c = 3 args = (4,) kw = {'d': 99, 'x': '#'}
>>> args = (1, 2, 3)
>>> kw = {'d': 88, 'x': '#'}
>>> f2(*args, **kw)
a = 1 b = 2 c = 3 d = 88 kw = {'x': '#'}
所以,对于任意函数,都可以通过类似func(*args, **kw)
的形式调用它,无论它的参数是如何定义的。
小结:
Python的函数具有非常灵活的参数形态,既可以实现简单的调用,又可以传入非常复杂的参数。
默认参数一定要用不可变对象,如果是可变对象,程序运行时会有逻辑错误!
要注意定义可变参数和关键字参数的语法:
*args
是可变参数,args接收的是一个tuple;
**kw
是关键字参数,kw接收的是一个dict。
以及调用函数时如何传入可变参数和关键字参数的语法:
可变参数既可以直接传入:func(1, 2, 3)
,又可以先组装list或tuple,再通过*args
传入:func(*(1, 2, 3))
;
关键字参数既可以直接传入:func(a=1, b=2)
,又可以先组装dict,再通过**kw
传入:func(**{'a': 1, 'b': 2})
。
使用*args
和**kw
是Python的习惯写法,当然也可以用其他参数名,但最好使用习惯用法。
命名的关键字参数是为了限制调用者可以传入的参数名,同时可以提供默认值。
定义命名的关键字参数在没有可变参数的情况下不要忘了写分隔符*
,否则定义的将是位置参数。