调用函数
函数是指用于进行某种计算的一些列语句的有名称的组合。Python3内置了很多有用的函数,可以直接调用。
要调用一个函数,就要知道函数的名称和参数。参加官网帮助文档地址:https://docs.python.org/3.5/library/functions.html
函数名其实是指向一个函数对象的引用,完全可以把函数名赋给一个变量,相当于给这个函数起了个别名。
#函数别名
fun = abs;
print(fun(-123))
输出:
123
定义函数
自定义函数的简单规则。
- 函数代码块以def关键词开头,后接函数标识名称和圆括号()
- 所有传入的参数和自变量都必须放在圆括号中,可以在圆括号中定义参数。
- 函数的第一行语句可以选择性使用文档字符串,用于存放函数说明。
- 函数内容以冒号开始,并且要缩进。
- return[表达式]结束函数,选择性返回一个值给调用方。不带表达式的return相当于返回None。
一般格式如下:
def 函数名(参数列表):
函数体
return
或者更直观的表述为:
def (arg1,arg2, arg3…argN):
<statements>
return
函数的名字必须以字母开头,可以包括下划线"_"。和定义变量一样,不能把Python的关键字定义成函数的名字。函数内的语句是任意数量的,每个语句至少有一个空格的缩进,以表示该语句属于这个函数。函数体必须保持缩进一致,因为,在函数中,缩进结束就代表函数结束。示例如下:
#! /usr/bin/python3
# -*- coding:UTF-8 -*-
#函数定义
def hello():
print('hello world')
hello()
输出:
hello world
注意:
- 没有return语句时,函数执行完毕也会返回结果,返回结果为None
- retrun None可以简写成return
- 在Python中定义函数时,需要保持函数体中同一层次的代码缩进一致。
- 如果想定义一个空函数时,可以使用pass语句,示例如下:
def doNoting():
pass
doNoting()
输出:无
函数的参数
调用函数时可以使用以下参数类型:
- 必须参数
- 关键字参数
- 默认参数
- 可变参数
- 组合参数
必须参数
必须参数必须以正确的顺序传入函数。调用时数量必须和声明一样。示例如下:
# 必须参数
#! /usr/bin/python3
# -*- coding:UTF-8 -*-
def parmsone(str):
print(str)
parmsone('I\'m a param')
输出:
I'm a param
关键字参数
使用关键字参数允许调用函数时参数的顺序与声明时不一致,因为Python解释器能够使用参数名匹配参数值。
#关键字参数
#! /usr/bin/python3
# -*- coding:UTF-8 -*-
def parmssome(name,age):
print('名字是:',name)
print('年龄是:',age)
print('必须参数,按照顺序传入')
parmssome('小明',21)
print('关键字参数,按照顺序传入')
parmssome('小明',21)
print('关键字参数,不按照顺序传入')
parmssome(age=21,name='小明')
输出:
必须参数,按照顺序传入
名字是: 小明
年龄是: 21
关键字参数,按照顺序传入
名字是: 小明
年龄是: 21
关键字参数,不按照顺序传入
名字是: 小明
年龄是: 21
默认参数
调用函数时,如果没有传递参数,就会使用默认参数。
使用默认参数,就是在定义函数时,给参数一个默认值。如果没有给调用的函数的参数赋值,调用的函数就会使用这个默认值。
#默认参数
#! /usr/bin/python3
# -*- coding:UTF-8 -*-
def defaultParam(name,age=23):
print('名称是:',name)
print('年龄是:',age)
print('默认参数')
defaultParam('小明')
输出:
默认参数
名称是: 小明
年龄是: 23
需要注意的是:
- 默认参数一定要放在非默认参数的后面
- 如果存在多个默认参数,也必须放在非默认参数的后面。即:无论有多少个默认参数,默认参数都必须放在必须参数的后面。
- 无论有多少个默认参数,若不传入默认参数值,则使用默认值。
- 若要更改某一个默认参数值,又不想传入其他默认值,且该默认值的位置不是第一个,则可以通过参数名更改想要更改的默认参数值。
- 若有一个默认参数通过参数名更改参数值,则其他想要更改的默认参数都需要传入参数名更改参数值,否则报错。
- 若更改默认参数时,传入的默认参数值得顺序不需要根据定义的函数中的默认顺序传入,不过最好同时参数名称。否则容易出现执行结果同预期结果不一致的情况。
可变参数
如果需要一个函数能够处理的参数声明时更多,这些参数叫做可变参数。格式如下:
def functionname(*var_args_tuple):
加了星号(*)的变量名会存放所有未命名的变量参数。传入的参数是一个元组,如果调用时没有指定参数,就是一个空元组。示例如下:
#可变参数
#! /usr/bin/python3
# -*- coding:UTF-8 -*-
def changeParams(*abc123):
print('---------打印可变参数start---------')
for s in abc123:
print('不定长参数',s)
print('---------打印可变参数end-----------')
changeParams('小明','小张','小宇')
changeParams('小明','小张')
changeParams('小明')
输出:
---------打印可变参数start---------
不定长参数 小明
不定长参数 小张
不定长参数 小宇
---------打印可变参数end-----------
---------打印可变参数start---------
不定长参数 小明
不定长参数 小张
---------打印可变参数end-----------
---------打印可变参数start---------
不定长参数 小明
---------打印可变参数end-----------
组合参数
在Python中定义函数可以用必须参数、关键字参数、默认参数、可变参数这4种参数,组合使用。注意定义的参数顺序,必须依次是必须参数、默认参数、可变参数和关键字参数。示例如下:
#组合参数
#! /usr/bin/python3
# -*- coding:UTF-8 -*-
def exp(p1,p2,p3=0,*p4,**p5):
#*后可变参数为元组,**后可变参数为字典
print('p1',p1,'p2',p2,'p3',p3,'p4',p4,'p5',p5)
exp(1,2)
exp(1,2,3)
exp(1,2,p3=3)
exp(1,2,3,'a','b')
exp(1,2,3,'a','b',x=3,y=4,z=5)
输出:
p1 1 p2 2 p3 0 p4 () p5 {}
p1 1 p2 2 p3 3 p4 () p5 {}
p1 1 p2 2 p3 3 p4 () p5 {}
p1 1 p2 2 p3 3 p4 ('a', 'b') p5 {}
p1 1 p2 2 p3 3 p4 ('a', 'b') p5 {'z': 5, 'y': 4, 'x': 3}
此处还可以用tuple和dict调用上述函数,使用方式如下:
def exp(*p1,**p2):
print('p1',p1,'p2',p2)
tuple1=tuple([1,2,3,'a','b'])
print(tuple1)
dict1=dict([('小明',23),('小张',21),('小宇',22)])
print(dict1)
exp(*tuple1,**dict1)
输出:
(1, 2, 3, 'a', 'b')
{'小明': 23, '小张': 21, '小宇': 22}
p1 (1, 2, 3, 'a', 'b') p2 {'小明': 23, '小张': 21, '小宇': 22}
形参实参
函数的两种类型参数,一种是函数定义里的形参,一种是调用函数时的实参。
局部变量
- 定义的变量如果在函数体中第一次出现,就是局部变量。
- 局部变量只能在函数体中访问,超出函数体的范围访问就会出错。
- 如果把变量x作为实参传入函数体中,在函数体中不定义变量x,那么x会被认为是局部变量。
- 如果在函数外定义了变量x并赋值,在函数体中可以直接使用该变量,这时x被称为全局变量。同时,如果在函数体中更改了函数x的值,函数体外x的值不会随之改变。示例如下:
#! /usr/bin/python3
# -*- coding:UTF-8 -*-
x=50
def f(x):
x=2
print('局部变量x的值是:',x)
f(x)
print('全局变量x的值是:',x)
输出:
局部变量x的值是: 2
全局变量x的值是: 50
全局变量
- 在函数外,一段代码最开始赋值的变量可以被多个函数引用,这就是全局变量。全局变量可以在整个程序范围内访问。
- 全局变量可以在全局使用,在函数中更改全局变量的值不会影响全局变量在其他函数语句中的使用。
- 在函数中,使用某个变量时,如果该变量既有全局变量又有局部变量,就默认使用局部变量。
- 在函数体中的变量前加了一个global关键字后,函数调用结束后,在函数外使用变量时,值变为和函数体中的值一样了。即:要在函数中将某个变量定义为全局变量,在需要被定义的变量前加上一个global关键字即可。示例如下:
x=50
def f():
global x
x=2
print('局部变量x的值是:',x)
f()
print('全局变量x的值是:',x)
输出:
局部变量x的值是: 2
全局变量x的值是: 2
有返回值和无返回值
函数分为有返回值和无返回值,如果定义函数时,没有return语句,则默认返回一个None
使用函数的好处
- 有利于阅读代码,且易于测试
- 减少重复代码的使用,且可以被反复使用
- 可以将很长的代码片段拆分成多个函数,对每个函数单独测试,使用时再组装到一起。
返回函数和闭包
-
函数的返回值可以是函数
-
闭包的定义:如果在一个内部函数里对外部函数(不是在全局作用域)的变量进行引用,内部函数就被认为是闭包。
此时,当调用外部函数时,每次都会产生一个新的内部函数,即使传入的参数相同也是如此。
示例如下:
def sum_late(*args):
def cal_sum1():
x2 = 0
for n in args:
x2 += n
return x2
return cal_sum1
print('sum_late()函数的结果是:', sum_late(1, 2, 3, 4, 5))
calSum = sum_late(1, 2, 3, 4, 5)
print('calc_sum()函数的结果是:',calSum())
fun1=sum_late(1,2,3,4,5)
fun2=sum_late(1,2,3,4,5)
print('fun1==fun2',fun1==fun2)
输出:
sum_late()函数的结果是: <function sum_late.<locals>.cal_sum1 at 0x0000000000D69D90>
calc_sum()函数的结果是: 15
fun1==fun2 False
递归函数
如果一个函数在内部调用自身,这个函数就被称为递归函数。格式如下:
def recurision():
return recurision()
这类递归被称为无穷递归,理论上永远不会结束,但实际上,因为每次调用一次函数,就会消耗一点内存,在足够多的函数调用后,内存被耗尽,程序就会报异常。
因此,实际使用的递归函数应该有结束的条件。示例如下:
def fact(n):
if n==1:
return 1
return n*fact(n-1)
print(fact(5))
输出:
120
理论上,所有的递归函数都可以用循环表达,只是没有使用递归函数简练、清晰
filter()函数
filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。
该接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判,然后返回 True 或 False,最后将返回 True 的元素放到新列表中。语法格式如下:
filter(function,iterable)
参数:
- function–判断函数
- iterable–可迭代对象
返回值:
- 返回列表
示例:
#过滤出列表中的所有奇数:
def is_odd(x5):
return x5%2 ==1
newlist = filter(is_odd,[1,2,3,4,5,6,7,8,9,10])
print(list(newlist))
#把一个序列中的空字符串删掉
def not_empty(x6):
return x6.strip()
newlist2 = filter(not_empty,['A ','B ','C ','D ','E ','F '])
print(list(newlist2))
输出:
[1, 3, 5, 7, 9]
['A ', 'B ', 'C ', 'D ', 'E ', 'F ']
匿名函数
python使用lambda创建匿名函数,lambda函数的语法只包含一个语句,格式如下:
lambda[arg1[,arg2....argn]]:expression
示例如下:
#用函数表达
def funcxy(x,y):
return x+y
print('函数计算的结果是:',funcxy(1,2))
#用lambda表达式表达,上面的函数等价于
c=lambda x,y:x+y
print('lambda表达式计算的结果是:',c(1,2))
输出:
函数计算的结果是: 3
lambda表达式计算的结果是: 3
示例2,lambda表达式与filter()函数结合:
#用函数表达
def funcabc(x):
return x>3
newlist3 = list(filter(funcabc,[1,2,3,4,5]))
print('函数计算的结果是:',newlist3)
#lambda表达式与filter()函数结合
print('lambda表达式计算的结果是:',list(filter(lambda x:x>3,[1,2,3,4,5])))
输出:
函数计算的结果是: [4, 5]
lambda表达式计算的结果是: [4, 5]
其中,x为lambda函数的一个参数,:为分隔符。x>3是返回值,在lambda函数中不能有return,其实冒号(:)后面就是返回值。
另外需要注意几下几点:
-
一般有一行表达式,必须有返回值。
-
不能有return
-
可以没有参数,也可以有一个或者多个参数。如:t=lambda : True,分号前没有任何参数。
-
lambda函数中的参数也可以有默认值,如:
c=lambda x,y=2,z=3:x+y+z print(c(1))
输出:
6
偏函数
偏函数通过functools模块被用户调用。偏函数是将要承载的函数作为parital()函数的第一个参数,原函数的各个参数依次作为partial()函数的后续参数,除非使用关键字参数。如:
#! /usr/bin/python3 # -*- coding:UTF-8 -*- from functools import partial def mod(x,y): return x%y mod_100=partial(mod,100) mod_1=partial(mod) print('调用偏函数调用的结果是:',mod_100(7)) print('调用偏函数2调用的结果是:',mod_1(100,7)) print('调用自定义函数调用的结果是:',mod(100,7))
输出:
调用偏函数调用的结果是: 2 调用偏函数2调用的结果是: 2 调用自定义函数调用的结果是: 2
偏函数的优点是:所需代码比自定义函数更少、更简洁。