什么是函数,如何在 Python 程序中定义函数呢?
说白了,函数就是为了实现某一功能的代码段,只要写好以后,就可以重复利用。
python中的自定义函数
Python 的函数具有非常灵活多样的参数形态,既可以实现简单的调用,又可以传入非常复杂的参数。从简到繁的参数形态如下:
位置参数 (positional argument)
默认参数 (default argument)
可变参数 (variable argument)
关键字参数 (keyword argument)
命名关键字参数 (name keyword argument)
参数组合
下面的例子中message作为最简单的位置参数:
def my_func(message):
print('Got a message: {}'.format(message))
#调用函数my_func() my_func('Hello World')
#输出 Got a message: Hello World
如上图
def - 定义正规函数要写 def 关键词。
function_name - 函数名,起名最好有意义。
arg1 - 位置参数 ,这些参数在调用函数 (call function) 时位置要固定。
arg2 = v - 默认参数 = 默认值,调用函数的时候,默认参数已经有值,就不用再传值了。
:- 冒号,在第一行最后要加个冒号。
“”“docstring”"" - 函数说明,给使用函数这介绍该它是做什么的。
statement - 函数内容。
默认函数一定要放在位置参数后面,不然程序会报错。
「默认参数」可以是多个。
def student( id, shuxue=90, yinyu=95 ):
print( 'id:', id )
print( 'shuxue chenji:', shuxue )
print( 'yinyu chenji:', yinyu)
student('xiaoming')
#输出结果
id:xiaoming
shuxue chenji: 90
yinyu chenji: 95
你可以把默认参数像「位置参数」那样对待,给它设定任何值
def student( id, shuxue=90, yinyu=95 ):
print( 'id:', id )
print( 'shuxue chenji:', shuxue )
print( 'yinyu chenji:', yinyu)
student('xiaoming',100,100)
#输出结果
id: xiaoming
shuxue chenji: 100
yinyu chenji: 100
Python 自定义函数中,还可以定义「可变参数」。顾名思义,可变参数就是传入的参数个数是可变的,可以是 0, 1, 2 到任意个。
*args - 可变参数,可以是从零个到任意个,自动组装成元组。
def student( id, shuxue=90, yinyu=95 , *args ):
PV = 0
for n in args:
PV = PV + n
print( 'id:', id )
print( 'shuxue chenji:', shuxue )
print( 'yinyu chenji:', yinyu)
print( 'zong chenji:', PV*shuxue )
student('xiaoming',100,100,1,2,3)
#输出结果:
id: xiaoming
shuxue chenji: 100
yinyu chenji: 100
zong chenji: 600
**kw - 关键字参数,可以是从零个到任意个,自动组装成字典。
可变参数允许传入零个到任意个参数,它们在函数调用时自动组装为一个元组 (tuple)
关键字参数允许传入零个到任意个参数,它们在函数内部自动组装为一个字典 (dict)
def student( id, shuxue=90, yinyu=95 , *args,**kw ):
PV = 0
for n in args:
PV = PV + n
print( 'id:', id )
print( 'shuxue chenji:', shuxue )
print( 'yinyu chenji:', yinyu)
print( 'zong chenji:', PV*shuxue )
print( 'keyword:', kw)
student('xiaoming',100,100,1,2,3,courtry='china)
#输出结果:
id: xiaoming
shuxue chenji: 100
yinyu chenji: 100
zong chenji: 600
keyword: {'courtry': 'china'}
除了直接传入多个参数之外,还可以将所有参数先组装成字典shuzi,用以「**shuzi」的形式传入函数 (shuzi 是个字典,前面加个通配符 ** 是拆散字典,把字典的键值对传入函数中)
def student( id, shuxue=90, yinyu=95 , *args,**kw ):
PV = 0
for n in args:
PV = PV + n
print( 'id:', id )
print( 'shuxue chenji:', shuxue )
print( 'yinyu chenji:', yinyu)
print( 'zong chenji:', PV*shuxue )
print( 'keyword:', kw)
kemu = (1, 2, 3, 4, 5)
shuzi = {'dc':'act/365', 'bdc':'following'}
student( 'xiaoming', 100, 100, *kemu, **shuzi )
#运行结果
id: xiaoming
shuxue chenji: 100
yinyu chenji: 100
zong chenji: 1500
keyword: {'dc': 'act/365', 'bdc': 'following'}
*, kemu - 命名关键字参数,用户想要输入的关键字参数,定义方式是在nkw 前面加个分隔符 *。使用命名关键字参数时,要特别注意不能缺少参数名。
def student( id, shuxue=90, yinyu=95 , *,args,**kw ):
print( 'id:', id )
print( 'shuxue chenji:', shuxue )
print( 'yinyu chenji:', yinyu)
print( 'zong chenji:', args)
print( 'keyword:', kw)
shuzi = {'dc':'act/365', 'bdc':'following'}
student( 'xiaoming', 100, 100, *,args=quanke, **shuzi )
#输出结果
id: xiaoming
shuxue chenji: 100
yinyu chenji: 100
zong chenji: quanke
keyword: {'dc': 'act/365', 'bdc': 'following'}
参数组合
在 Python 中定义函数,可以用位置参数、默认参数、可变参数、命名关键字参数和关键字参数,这 5 种参数中的 4 个都可以一起使用,但是注意,参数定义的顺序必须是:
位置参数、默认参数、可变参数和关键字参数。
位置参数、默认参数、命名关键字参数和关键字参数。
args 是可变参数,args 接收的是一个 tuple
kw 是关键字参数*,kw 接收的是一个 dict
命名关键字参数是为了限制调用者可以传入的参数名,同时可以提供默认值。定义命名**关键字参数不要忘了写分隔符 ***,否则定义的是位置参数。
python中的匿名函数
除了常规的自定义函数,你应该也会在代码中见到一些“非常规”函数,它们往往很简短,就一行,并且有个很酷炫的名字——lambda,没错,这就是匿名函数。
匿名函数的关键字是 lambda,之后是一系列的参数,然后用冒号隔开,最后则是由这些参数组成的表达式。我们通过几个例子看一下它的用法:
square = lambda x: x**2
square(3)
#输出结果:9
lambda *args: sum(args);输入是任意个数的参数,输出是它们的和
func = lambda *args: sum(args)
func( 2,4,6,8,10 )
#输出结果:30
python中高阶函数
map函数
map函数:map函数是相当于通过一个函数将输入变量一一映射(通过某类函数)进行输出。map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。map(函数 f, 序列 x):对序列 x 中每个元素依次执行函数 f,将 f(x) 组成一个「map 对象」返回 (可以将其转换成 list 或 set)
def func(x):
return x*x
r = map(func,[1,2,3])
print(list(r))
#输出结果
[1, 4, 9]
与匿名函数结合
lst = [1, 2, 3, 4, 5]
map_iter = map( lambda x: x**2, lst )
print( map_iter )
print( list(map_iter) )
#输出结果
<map object at 0x00000000051FE978>
[1, 4, 9, 16, 25]
在 上面第二个map 函数中
第一个参数是一个计算平方的「匿名函数」
第二个参数是列表,即该「匿名函数」作用的对象
注意 map_iter 是 map 函数的返回对象 (它是一个迭代器),想要将其内容显示出来,需要用 list 将其转换成「列表」形式。
filter函数
Python内建的filter()函数用于过滤序列。和map()类似,filter()也接收一个函数和一个序列。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。所以filter和map区别一点就是filter就像滤波器一样会保留或者丢掉一些元素,但是map是不会丢弃元素的,只是会作用在一些元素上面的。filter(函数 f, 序列 x):对序列 x 中每个元素依次执行函数 f,将 f(x) 为 True 的结果组成一个「filter 对象」返回 (可以将其转换成 list 或 set)
def is_odd(num):
#if(num%2==1):
#return num
return num % 2 == 1 # 这句话的含义就是先进行判断然后进行合适数字的输出
print(list(filter(is_odd, [1, 2, 3, 4, 5, 6]))) # filter和map类似的,输出的也是一个惰性序列,需要通过List强制进行转换
#输出结果:[1, 3, 5]
与匿名函数结合
lst = [1, 2, 3, 4, 5]
filter_iter = filter(lambda n: n % 2 == 1, lst)
print( filter_iter )
print( list(filter_iter) )
#输出结果:[1, 3, 5]
第一个参数是一个识别奇数的「匿名函数」
第二个参数是列表,即该「匿名函数」作用的对象
同样,filter_iter 作为 filter 函数的返回对象,也是一个迭代器,想要将其内容显示出来,需要用 list 将其转换成「列表」形式。
reduce函数
reduce把一个函数作用在一个序列[x1, x2, x3, …]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)。reduce(函数 f, 序列 x):对序列 x 的第一个和第二个元素执行函数 f,得到的结果和序列 x 的下一个元素执行函数 f,一直遍历完的序列 x 所有元素。 reduce 函数,顾名思义就是累积函数,把一组数减少 (reduce) 到一个数。
from functools import reduce
def add(a,b):
return a+b
print(reduce(add,[1,2,3,4])) # 使用redunce这里相当于是sum
def add1(a,b):
return 10 * a + b
print(reduce(add1,[1,2,3,4]))
#输出结果:
10
1234
与lambda函数结合
from functools import reduce
lst = [1, 2, 3, 4, 5]
reduce( lambda x,y: x+y, lst )
#输出结果:15
在 reduce 函数中
第一个参数是一个求和相邻两个元素的「匿名函数」
第二个参数是列表,即该「匿名函数」作用的对象
在 reduce 函数的第三个参数还可以赋予一个初始值
from functools import reduce
lst = [1, 2, 3, 4, 5]
reduce( lambda x,y: x+y, lst,100)
#输出结果:115
偏函数
偏函数 (paritial function) 主要是把一个函数的参数 (一个或多个) 固定下来,用于专门的应用上 (specialized application)。要用偏函数用从 functools 中导入 partial 包:
from functools import partial
lst = [3, 1, 2, 5, 4]
sorted( lst )
#输出结果:
[1, 2, 3, 4, 5]
sort 函数默认是按升序排列,假设在你的应用中是按降序排列,你可以把函数里的 reverse 参数设置为 True。
from functools import partial
lst = [3, 1, 2, 5, 4]
sorted( lst,reverse=True)
#输出结果:
[5, 4, 3, 2, 1]
每次设定参数很麻烦,你可以专门为「降序排列」的应用定义一个函数,比如叫 sorted_dec,用偏函数 partial 把内置的 sort 函数里的 reverse 固定住,代码如下:
sorted_dec = partial( sorted, reverse=True )
st = [3, 1, 2, 5, 4]
sorted_dec(lst)
#输出结果:
[5, 4, 3, 2, 1]
嵌套函数
以普通的加法函数为例:
def add1(x, y):
return x + y
def add2(x):
def add(y):
return x + y
return add
g = add2(2)
print( add1(2, 3) )
print( add2(2)(3) )
print( g(3) )
#输出结果
5
5
5
解析式
解析式 是将一个可迭代对象转换成另一个可迭代对象的工具。不严谨地说,容器类型数据 (str, tuple, list, dict, set) 都是可迭代对象。
第一个可迭代对象:可以是任何容器类型数据。
第二个可迭代对象:看是什么类型解析式:
列表解析式:可迭代对象是 list
字典解析式:可迭代对象是 dict
集合解析式:可迭代对象是 set
下面写出列表、字典和集合解析式的伪代码 (pseudo code)。
#list 解析式
[值 for 元素 in 可迭代对象 if 条件]
#dict 解析式
{键值对 for 元素 in 可迭代对象 if 条件}
#set 解析式
{值 for 元素 in 可迭代对象 if 条件}
列表解析式:从一个含整数列表中把奇数 (odd number) 挑出来,我们先用for语句来实现。
lst = [1, 2, 3, 4, 5]
odds = []
for n in lst:
if n % 2 == 1:
odds.append(n)
print(odds)
#输出结果:[1, 3, 5]
然后用列表解析式来实现:
lst = [1, 2, 3, 4, 5]
odds = [n for n in lst if n % 2 == 1]
print(odds)
#输出结果:[1, 3, 5]
我们
问题:用解析式将二维元组里每个元素提取出来并存储到一个列表中。
tup = ((1, 2, 3), (4, 5, 6), (7, 8, 9))
先遍历第一层元组,用 for t in tup,然后遍历第二层元组,用 for x in t,提取每个 x 并"放在“列表中,用 []。代码如下:
tup = ((1, 2, 3), (4, 5, 6), (7, 8, 9))
flattened = [x for t in tup for x in t]
print(flattened)
#输出结果:[1, 2, 3, 4, 5, 6, 7, 8, 9]
字典解析式
集合解析式
解析式与高阶函数对比:
用「在列表中先找出奇数再乘以 2」的例子,对于列表 lst = [1, 2, 3, 4, 5],我们先看「列表解析式」的实现:
lst = [1, 2, 3, 4, 5]
[ n*2 for n in lst if n%2 == 1]
#输出结果:[2, 6, 10]
再看「map/filter」的实现:
lst = [1, 2, 3, 4, 5]
list( map(lambda n: n*2, filter(lambda n: n%2 == 1, lst)) )
#输出结果:[2, 6, 10]
谁简谁繁,一目了然。
总结
函数包括自定义函数 (用 def) ,匿名函数 (用 lambda)还有高阶函数(map,reduce,filter),函数的参数形态也多种多样,有位置参数、默认参数、可变参数、关键字参数、命名关键字参数。
解析式并没有解决新的问题,只是以一种更加简洁,可读性更高的方式解决老的问题。解析式可以把「带 if 条件的 for 循环」用一行程序表达出来,也可以实现 map 加 filter 的功能。