Python3函数(v3.7)

风尘

文章目录

  1. 1. 函数查询
  2. 2. 函数定义
  3. 3. 空函数
  4. 4. 常用函数
  5. 5. 多返回值
  6. 6. 函数参数
    1. 6.1. 位置参数
    2. 6.2. 默认参数
    3. 6.3. 可变参数
    4. 6.4. 关键字参数
    5. 6.5. 参数组合
    6. 6.6. 参数检查
  7. 7. 生成器
  8. 8. 迭代器

[TOC]

函数查询

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

1
2
3
>>> dir(__builtins__) #查看内置函数
>>> 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对象。