Python3函数(v3.7)

[TOC]

函数查询

Python有很多内置函数使用dir()help()方法查看。
dir()方法不带参数返回的是当前范围内的变量、方法和定义的列表;带参数返回的是当前参数的属性、方法列表

1
2
3
>>> dir(__buildins__) #查看内置函数
>>> dir(int) #查看int下的函数
>>> help(int.numerator) #查看int下的numerator()函数用法

函数定义

Python中使用def定义函数,语法为def 函数名(参数) :,然后在缩进块中编写函数体,返回值用return

Python没有大括号语法,使用缩进代替大括号。

1
2
3
4
5
def func(param) :
if param < 10 :
return param;
else :
return 10;

对于递归函数,如果调用过深会出现栈溢出问题,某些语言中如javascript 中可以采用尾递归优化解决这个问题,但大多数解释器(包括Python)都没有对此进行优化,所以即使在代码中对递归函数进行尾递归优化,也不会起作用

空函数

想定义一个没有任何动作的函数时通过pass语句实现。

1
2
def non() :
pass

pass语句还可以用在其它语句里,表示什么也不做:

1
2
if True :
pass

如果想让一个语句什么也不做使用pass语句,否则程序会报错。

常用函数

  • len() 获取字符串长度
  • ord() / chr()
1
2
3
4
>>> ord('中') #获取字符的整数表示,注意ord函数只接收一个字符参数
20013
>>> chr(20013) #编码转换为对应的字符
'中'
  • 字符串函数 help(str)
函数名 作用
capitalize() 把字符串第一个字符改为大写,其余字符改为小写
casefold() 把字符串所有大写字符改为小写
center(width, fillchar=’ ‘) 将字符串居中并使用fillchar(默认空格)填充至长度为width的新字符串
count(sub[, start[, end]]) 返回字符串中sub出现的次数
encode(encoding=’utf-8’, errors=’strict’) 字符串编码
startswith(prefix[, start[, end]]) 返回字符串是否以前缀字符开始
endswith(suffix[, start[, end]]) 返回字符串是否以后缀字符结束
expandtabs(tabsize=8) 将字符串中tab字符(\t)转换为tabsize个空格(默认为8)
find(sub[,start[,end]]) 查找字符串sub字符串的最小索引,找不到时返回-1
index(sub[, start[, end]]) 作用同上,不同的是找不到时抛出ValueError错误
join(iterable) 把字符串作为分割符将iterable进行分割。
例: ‘.’.join([‘ab’, ‘pq’, ‘rs’]) -> ‘ab.pq.rs’
lower() 将字符串转小写
upper() 将字符串转大写
lstrip(chars=None) 去掉字符串左空格用chars代替(默认值None)
rstrip(chars=None) 去掉字符串右空格用chars代替(默认值None)
strip(chars=None) 去掉字符串左右空格用chars代替(默认值None)
replace(old,new,count=-1) 将old字符串替换成new字符串,不超过count次(默认-1不限制次数)
split(sep=None, maxsplit=-1) 将字符串分割(默认以空格分割)
swapcase() 翻转字符串中的大小写

多返回值

Python函数可以有多个返回值。

1
2
3
4
5
6
def helloPython() :
return 'hello','Python'

x,y=helloPython()
print(x) --> hello
print(y) --> Python

实际上,Python返回的是一个元组。但是,Python语法允许多个变量接收一个元组,只需按位置赋给对应值。

1
2
>>> print(helloPython())
('hello', 'Python') #直接打印函数返回值结果是一个元组

函数参数

位置参数

调用函数时,必须根据的函数定义的参数位置一一对应传递,且不可少。

默认参数

定义函数时,可以直接在参数后面用等式设置默认参数,调用时此参数可以不用传递任何值。

1
2
3
4
5
6
7
def func(param=5) : #默认参数为5
if not isinstance(param,(int,float)) :
raise TypeError('invalid param')
if param < 10 :
return param;
else :
return 10;

设置默认参数时,必须位置参数在前,默认参数在后,否则解释器会报错。调用时可以传递部分默认参数值,但必须指定默认参数名字。

1
2
3
4
def func(name,age,sex='M',address='Beijing') :
pass

func('张三',21,address='Shanghai') #传递部分默认参数

注意:默认参数必须指定不变对象,否则会被函数内赋值改变。

1
2
3
4
5
6
7
def func(param=[]) : #默认参数指向可变参数
param.append('END')
return param

func()
func()
print(func()) --> ['END','END','END']

上面多次调用函数后,由于默认参数没有指定不变对象,而出现混乱。修改上面例子:

1
2
3
4
5
6
7
8
def func(param=None) :
if param is None :
param = []
return param

func()
func()
print(func()) --> []

可变参数

可变参数即函数参数可以是动态的可变的,调用函数时可随意传入0….N个可变参数。采用*args形式,在函数内部自动组装成一个元组。

1
2
3
4
5
6
7
8
#定义可变参数函数
def func(*numbers) :
for n in numbers :
print(n)

#调用可变参数函数
L = [1,2,3,4,5,6,7];
func(*L)

关键字参数

类似可变参数,采用**args形式,调用函数时可随意传入0….N个关键字参数,在函数内部自动组装成一个字典。

1
2
3
4
5
6
7
#定义关键字参数
def func(**kw) :
print(kw)

#调用关键字参数
kw={'address':'Beijing','code':90}
func(**kw)
  • 命名关键字参数

默认可以传入任何名字关键字参数,如果想要限制传入的关键字参数的名字,可使用*符号分割。

1
2
3
4
5
def func(*,address,code) :
print(kw)

func(address='Beijing',code=8) --> 正确
func(name='Bob') --> #错误 只允许传入address或code名字的关键字参数

如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*

1
2
def func(*name,address,code) : #address、code是关键字参数
pass

参数组合

在Python中定义函数,可以用位置参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。但是请注意,参数定义的顺序必须是:位置参数、默认参数、可变参数、命名关键字参数和关键字参数。

对于任意函数都可以使用*args**args的形式调用它,无论它的参数是如何定义的。

1
2
3
4
5
6
7
8
9
def func(name,age,sex='M',*args,**kw) :
print('name=',name,'age=',age,'sex=',sex,'*args=',args,'**kw=',kw)

args = ['张三',20,'M','Beijing']
kw = {'code':8,'job':'teacher'}
func(*args,**kw)

结果:
name= 张三 age= 20 sex= M *args= ('Beijing',) **kw= {'code': 8, 'job': 'teacher'}

参数检查

由于Python是动态类型,函数参数无法确定是什么类型,因此如果传入不恰当类型会导致程序报错。所以一个完整的函数需要使用内置函数isinstance()做参数校验。

1
2
3
4
5
6
7
def func(param) :
if not isinstance(param,(int,float)) :
raise TypeError('invalid param')
if param < 10 :
return param;
else :
return 10;

当程序出现错误,python会自动引发异常,也可以通过raise显示地引发异常。一旦执行了raise语句,raise后面的语句将不能执行。

生成器

对过列表生成式生成的列表受内存等原因限制列表容量有限,如果通过计算把list列表的后面元素推算出来,实现边循环边计算的机制,就不必提前生成列表,理论上就实现了无限大小,Python中把这种机制叫做生成器。

  • 创建生成器最简单的方法就是把列表生成式的[ ]改成( )即可:
1
2
3
4
5
6
7
8
9
>>> g = (x for x in range(100))
>>> g
<generator object <genexpr> at 0x10fa3ba20>
>>> next(g) #通过next()方法调用
0
>>> next(g)
1
>>> next(g)
2

如上生成器保存的是算法,而不是真正的数值,每次通过next()函数调用计算出g的下一个值,直到g没有更多元素时将会抛出StopIteration错误。通常我们通过for循环调用生成器,并且没有下一个元素时也不会抛出错误。

1
2
for n in g : #通过for循环调用生成器
print(n)
  • 如果函数定义中包含yield关键字,此时函数就是一个声明的生成器:
1
2
3
4
5
6
7
8
9
10
def fib(max) :
    n,a,b = 0,0,1
    while n < max :
        yield b
        a,b = b,a+b
        n = n + 1
    return 'done'

g = fib(10)
print(g) --> <generator object fib at 0x1067a9480>

上面定义的的函数因为包括yield关键字,已经不是普通的函数了,而是一个生成器(如上:打印生成器g返回generator)。generator的执行顺序和普通函数不样,每次调用next()函数遇到yield返回其后面的值,再次执行时从上次返回的yield处继续执行,直到函数中没有yield抛出StopIteration错误为止。

1
2
for x in g : #调用生成器函数
    print(x)

通过for循环调用生成器得不到函数中的return返回值,如果想要得到返回值,必须捕获StopIteration异常,其值在StopIteration的value中。

1
2
3
4
5
6
7
while True :
try :
x = next(g)
print(x) #得到生成器yield返回值
except StopIteration as e :
print(e.value) #得到函数中return返回值
break

关于更多错误处理请参见Python3异常处理

迭代器

可以直接作用于for循环的对象称为可迭代对象(Iterable),包括listtupledictsetstr生成器等。可以使用isinstatnce()判断一个对象是否为Iterable对象:

1
2
from collections import Iterable
isinstance([],Iterable) --> True

生成器不但可以作用于for循环,还可以被next()函数调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值。
可以被next()函数调用并返回下一个值的对象称为迭代器(Iterator)。同样,可以使用isinstatnce()判断一个对象是否为Iterator对象:

1
2
from collections import Iterator
isinstance([],Iterator) --> False

生成器都是Iterator对象,但其它Iterable对象不是Iterator对象,可以使用iter()函数把其变成Iterator对象。

1
2
>>> isinstance(iter([]),Iterator)
True

Iterator对象表示一个数据流,不知道长度,只能通过next()函数调用计算下一个数据,因此Iterator对象是惰性的,只有在需要时才计算并返回下一个数据。甚至其可以表示无限大的数据流,而listIterable对象显然不能存储无限大数据,所以它们不是Iterator对象。