函数

本文详细介绍了Python中的函数,包括函数的定义、调用、文档说明、参数类型(位置参数、默认值参数、关键字参数、不定参数)以及*args和**kwargs的使用。还探讨了函数的顺序、返回值、内部/内嵌函数、变量作用域(全局与局部)、匿名函数lambda、高阶函数和常见高阶函数如filter、map、reduce、apply和zip的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

函数

  • 数学意义上的函数
    • y=2x+1,y|_{x=3}=2×3+1=7
  • 编程意义上的函数

Python中函数的定义:函数是逻辑结构化和过程化的一种编程方法。

函数是可以重复使用的程序段。在开发程序时,需要某块代码多次,但是为了提高编写的效率以及代码的重用,所以把具有独立功能的代码块组织为一个小模块,这就是函数。

它们允许你给一块语句一个名称,然后你可以在你的程序的任何地方使用这个名称任意多次地运行这个语句块。这被称为调用函数。我们已经使用了许多内建的函数,比如len()和range()。

函数定义

  • 空函数

如果想定义一个什么事也不做的空函数,可以用pass语句:

def func():
    pass

pass语句什么都不做,那有什么用?实际上pass可以用来作为占位符,比如现在还没想好怎么写函数的代码,就可以先放一个pass,让代码能运行起来。

def Function_name(pare,pra1,.....):
    '''函数'''
    

  • 非空函数

函数通过def关键字定义,def关键字后跟一个函数的标识符,然后跟一对圆括号,圆括号之中可以包括一些变量名,该行以冒号结尾,接下来是一块语句,它们是函数体。

声明函数的一般形式如下:

def 函数名(参数列表)
    '''说明'''
    函数语句
    return 返回值

说明如下:

​ 1.函数代码块以def关键词开头,后接函数标识符名称和小括号()。

​ 2.任何传入的参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。

​ 3.函数的第一行语句可以选择性地使用文档串----用于存放函数说明。

​ 4.函数内容以冒号起始,并且缩进。

​ 5.return[表达式]结束函数,选择性地返回一个值给调用方,不带表达式的return相当于返回None。

其中参数列表和返回值不是必须的,return也可以不跟返回值,甚至连return也没有。

对于return后没有返回值的和没有return语句的函数都会返回None值。

有些函数可能不需要传递参数,也没有返回值。

没有参数时,包含参数的圆括号也必须写上,圆括号后也必须有":"

举个例子

def info():
	"""打印信息"""
	print({"name":"Tom","age":18})
info()

函数的调用

函数定义后,我们就具备就实现某种功能的代码。执行这些代码,只需要调用函数。

函数调用形式:

info()

现在整体写出代码:

# 定义函数
def info():
	"""打印信息"""
	print({"name":"Tom","age":18})
#调用函数
info()

运行结果为:

{'name': 'Tom', 'age': 18}

练习:定义函数实现调用函数能够输出名字,年龄

def info(name,age):
	print(name)
	print(age)
	return name,age
print(info("张三",15))
结果:
张三
15
('张三', 15)

函数文档说明

在上面代码的基础上,添加

help(info)

运行后,结果为

info(a, b)
    加法

可以看到,help()返回add()函数的相关说明

直接查看文档说明

print(info.__doc__)
#打印信息

函数参数

假如我们需要定义一个函数计算两个数的积,有人设计如下函数:

def mul():
	x = 3
	y = 3
	print(x * y)

mul() # 9

这样可以吗?

这个函数只能实现3*3的结果,并不具备通用性。

为了让这个函数更具通用性,我们可以添加参数:

def mul(x, y):
	print(x * y)

mul(3, 6) # 调用
  • 参数调用的循序

    我们先看一下以下例子:

    >>> def test(x,y):
    ...     print(x)
    ...     print(y)
    ...
    >>> test(1,2)
    1
    2
    >>> test(x=1,y=2)
    1
    2
    >>> test(1,y=2)
    1
    2
    >>> test(x=1,2)
      File "<stdin>", line 1
    SyntaxError: positional argument follows keyword argument
    >>>
    

函数返回值

这里形象的解释一下函数:函数就是把一堆代码,打包放在那里,比如说一个发邮件的功能,然后这个功能被调用,说到这里大家应该会想知道,我们调了,但是调的一个结果是啥?有没有成功?如果成功,干A事情,如果不成功做B的事情。

返回值的定义:函数外部的代码要想获得函数的执行结果,就可以在函数里用return语句把结果返回。
函数参数种类

首先,了解两个概念:形参和实参

    1. 形参:
    • 只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元,因此,形参只在函数内部有效,函数调用结束返回主调用函数后则不能再使用该形参变量;
    1. 实参:
    • 实参可以是常量,变量,表达式,函数等,无论实参是何种类型的量,在进行函数调用的时,他们都必须有确定的值,以便把这些值传给形参,因此应预先用赋值,输入等办法使参数获得确定值;
>>> def test(x,y):----> 形参
...     print(x)
...     print(y)
...
>>> test(1,2)   ----->实参
  • 形参就是一把椅子,放在这里。占个位置而已,只到有人调用,赋值的时候才会分配内存单元,在调用结束,即可释放;
  • 实参,就是实实在在存在,什么类型都接受

1.位置参数

>>> def usr_manager(name,age,job,hobby):
...     print("用户管理系统".center(16,'-'))
...     print("\tName:\t",name)
...     print("\tAge:\t",age)
...     print("\tJob:\t",job)
...     print("\tHobby:\t",hobby)
...     print("用户管理系统".center(16,'-'))
...
>>> usr_manager('Ton',22,"IT","R绕道")
-----用户管理系统-----
        Name:    Ton
        Age:     22
        Job:     IT
        Hobby:   R绕道
-----用户管理系统-----
>>> usr_manager('Lilei',23,"IT","cjdh")
-----用户管理系统-----
        Name:    Lilei
        Age:     23
        Job:     IT
        Hobby:   cjdh
-----用户管理系统-----
>>>

默认值参数

假如我们设置hobby值为默认,即hobby=“Coding”

>>> def usr_manager(name,age,job,hobby="Coding"):
...     print("用户管理系统".center(16,'-'))
...     print("\tName:\t",name)
...     print("\tAge:\t",age)
...     print("\tJob:\t",job)
...     print("\tHobby:\t",hobby)
...     print("用户管理系统".center(16,'-'))
...
>>> usr_manager('Ton',22,"IT","R绕道") #传入参数,则改变值
-----用户管理系统-----
        Name:    Ton
        Age:     22
        Job:     IT
        Hobby:   R绕道
-----用户管理系统-----
>>> usr_manager('Ton',22,"IT")# 不传入参数,即为默认值
-----用户管理系统-----
        Name:    Ton
        Age:     22
        Job:     IT
        Hobby:   Coding
-----用户管理系统-----
>>>

通过观察,可知:

如果定义默认参数,在调用的时候,不给实参,就会调用默认参数

如果函数定义修改为:

>>> def usr_manager(name,age,job,hobby="Coding",job):

运行将报错:

  File "D:\课程所需软件环境指引\pythondemo\py\demo1.py", line 163
    def usr_manager(name,age,job,hobby="Coding",obj):

因此,默认参数必须要放到位置参数的后边

3.关键字参数

正常情况下,给参数参数要按顺序,不想按顺序就可以用关键字参数,只需指定参数名即可(指定了参数名的参数就叫关键参数)

 def usr_manager(name,age,job="IT",hobby="Coding"):
     print("用户管理系统".center(16,'-'))
     print("\tName:\t",name)
     print("\tAge:\t",age)
     print("\tJob:\t",job)
     print("\tHobby:\t",hobby)
     print("用户管理系统".center(16,'-'))
usr_manager('Ton',age=22,hobby="Read",job="IT")# 传参时,关键字参数可以位置改变
usr_manager('hdhcb',23,"23","string")# 不传关键字是,必须--对应

关键参数必须放在位置参数(以位置顺序确定对应关系的参致)之后。

4.不定参数

Python的不定参数,主要是指*args**kwargs这两个魔法变量。那么它们到底是什么?

其实并不是必须写成*args**kwargs。只有变量前面的 *(星号)才是必须的。也可以写成*var**vars。 而写成*args**kwargs只是一个通俗的命名约定。

*args**kwargs主要用于函数定义。我们可以将不定数量的参数传递给一个函数。

这里的不定的意思是:预先并不知道, 函数使用者会传递多少个参数给你, 所以在这个场景下使用这两个关键字。

  • *args 的用法

*args 是用来发送一个非键值对的任意数量的可变数量的参数列表给一个函数。

下面我们举例来帮助大家理解:

def a(para,*args):
	print("普通参数:",para)
	print("不定参数:",args)
	print(type(args))
	for arg in args:
		print('逐一输出不定参数:',arg)
a(1,2,3,4,5)
结果:
普通参数: 1
不定参数: (2, 3, 4, 5)
<class 'tuple'>
逐一输出不定参数: 2
逐一输出不定参数: 3
逐一输出不定参数: 4
逐一输出不定参数: 5

**kwargs 的方法

**kwargs可以我们将不定长度的键值对,作为参数传递给一个函数。

当我们想要在一个函数里处理带名字的参数时,就可以用**kwaege。

比如:

def a(**kwargs):
	print(type(kwargs))
	print(kwargs)
a(a=3,b=4,c=5)

运行后输出:

<class 'dict'>
{'a': 3, 'b': 4, 'c': 5}

*args和**kwargs的使用

def a(para1,para2,para3):
	print("para1:",para1)
	print("para2:",para2)
	print("para3:",para3)
args=("abc",6,9)
print(a(*args))
kwargs={"para1":3,"para2":"xyz","para3":[1,2,3]}
print(a(**kwargs))

运行后结果:

para1: abc
para2: 6
para3: 9
None
para1: 3
para2: xyz
para3: [1, 2, 3]
None

注意这里传递键值参数时,需满足参数数量一致,否则会报错。

标准参数与*args,**kwargs在使用时的顺序

那么如果你想在函数里同时使用所有这三种参数,顺序是这样的:

func(fargs,*args,**kwargs)

举例如下:

def a(para1,*para2,**para3):
	print("para1:",para1)
	print("para2:",para2)
	print("para3:",para3)
print(a(1,2,3,4,a=5,b=6,c=7))

运行结果:

para1: 1
para2: (2, 3, 4)
para3: {'a': 5, 'b': 6, 'c': 7}
None

声明与定义比较

​ 在某些编程语言里, 函数声明和函数定义区分开的。一个函数声明包括提供对函数名,参数的名字(传统上还有参数的类型), 但不必给出函数的任何代码, 具体的代码通常属于函数定义的范畴。

​ 在声明和定义有区别的语言中, 往往是因为函数的定义可能和其声明放在不同的文件中。 python将这两者视为一体,函数的子句由声明的标题行以及随后的定义体组成的。

前向引用

和其他语言类似,Python也不允许在函数未声明之前,对其进行引用或者调用。

我们下面给出几个列子来看一下:

def foo():
	print("in foo()")
	bar()
print(foo())

如果我们调用函数foo(),肯定会失败,因为函数bar()还没有定义

结果:报错

现在定义函数bar(),在函数foo()前给出bar()的声明


def bar():
	print("bar()")
def foo():
	print("in foo()")
	bar()



foo()

现在我们可以安全的调用foo(),而不会出现任何问题:


in foo()
bar()

事实上,我们甚至可以在函数bar()前定义函数foo():

def foo():
	print("in foo()")
	bar()

def bar():
	print("bar()")

Amazing!依然可以很好运行,不会有前向引用的问题:


in foo()
bar()

​ 这段代码是正确的因为即使(在 foo()中)对 bar()进行的调用出现在 bar()的定义之前,但 foo()本身不是在 bar()声明之前被调用的。换句话说,我们声明 foo(),然后再声明bar(),接着调用 foo(),但是到那时,bar()已经存在了,所以调用成功。

注意 ,foo()在没有错误的情况下成功输出了’in foo()’。名字错误是当访问没有初始化的标识符时才产生的异常 。

函数属性

​ 你可以获得每个 pyhon 模块,类,和函数中任意的名字空间。你可以在模块 foo 和 bar 里都有名为 x 的一个变量,,但是在将这两个模块导入你的程序后,仍然可以使用这两个变量。所以,即使在两个模块中使用了相同的变量名字,这也是安全的,因为句点属性标识对于两个模块意味了不同的命名空间,比如说,在这段代码中没有名字冲突:

import foo, bar 先定义两个脚本 然后导入 在当前脚本调用导入脚本的变量
print(foo.x + bar.x) 

​ 函数属性是 python 另外一个使用了句点属性标识并拥有名字空间的领域。

def foo():
	'foo() -- properly created doc string'

def bar():
	pass

bar.__doc__='Oops, forgot the doc str above'
bar.version=0.1
PS D:\课程所需软件环境指引\pythondemo\py> python -i demo1.py
>>> bar.__doc__
'Oops, forgot the doc str above'
>>> foo.__doc__
'foo() -- properly created doc string'
>>>

上面的 foo()中,我们以常规地方式创建了我们的文档字串,比如, 在函数声明后第一个没有赋值的字串。当声明 bar()时, 我们什么都没做, 仅用了句点属性标识来增加文档字串以及其他属性。我们可以接着任意地访问属性。下面是一个使用了交互解释器的例子。(你可能已经发现,用内建函
数 help()显示会比用__doc__属性更漂亮,但是你可以选择你喜欢的方式)

>>> help(foo)
Help on function foo in module __main__:

foo()
    foo() -- properly created doc string

>>> bar.version 
0.1
>>> foo.__doc__
'foo() -- properly created doc string'
>>> bar.__doc__
'Oops, forgot the doc str above'
>>>

注意我们是如何在函数声明外定义一个文档字串。然而我们仍然可以就像平常一样,在运行时刻访问它。然而你不能在函数的声明中访问属性。换句话说,在函数声明中没有’self‘这样的东西让你可以进行诸如_dict_[‘version’] = 0.1 的赋值。这是因为函数体还没有被创建,但之后你有了函数对象,就可以按我们在上面描述的那样方法来访问它的字典。另外一个自由的名字空间!

内部/内嵌函数

在函数体内创建一个函数(对象)是完全合法的,这种函数叫做内部/内嵌函数.

最明显的创建内部函数的方法是在外部函数的定义体内定义函数(用def关键字)

def foo():
	def bar():
		print("bar() called.")
	print("foo() called")
	bar()

foo()
bar()

我们将以上代码置人一个模块中,如inner.py,然后运行,我们会得到如下输出

PS D:\课程所需软件环境指引\pythondemo\py> python -i demo1.py
foo() called
bar() called.
Traceback (most recent call last):
  File "demo1.py", line 221, in <module>
    bar()
NameError: name 'bar' is not defined
    
>>>

http://www.pythontutor.com/visualize.html#mode=edit
将简单的代码拷入进去 可以看到执行过程
内部函数一个有趣的方面在于整个函数体都在外部函数的作用域(即是你可以访问一个对象的区域;稍后会有更多关于作用域的介绍)之内。如果没有任何对 bar()的外部引用,那么除了在函数体内,任何地方都不能对其进行调用,这就是在上述代码执行到最后你看到异常的原因

另外一个函数体内创建函数对象的方式是使用lambda 语句。 稍后讲述。如果内部函数的定义包含了在外部函数里定义的对象的引用(这个对象甚至可以是在外部函数之外),内部函数会变成被称为闭包(closure)的特别之物。

函数应用:打印图形和数学计算

函数的嵌套调用;

程序设计的思路,复杂问题分解为简单问题。

  • 思考1:编程实现:
    • 写一个函数打印一条横线
    • 打印自定义行数的横线
#打印一条横线
def foo():
	print("-"*30)
	#打印多条横线
def raad(num):
	i=0
	#因为foo函数已经完成了打印横线的功能
	#只需要多次调用函数即可
	while i<num:
		foo()
		i+=1
raad(3)
  • 思考2:编程实现
    • 写一个函数求三个数的和
    • 写一个函数求三个数的平均值

参考代码

# 求3个数的和
def sum3Number(a,b,c):
    return a+b+c # return 的后面可以是数值,也可是一个表达式

# 完成对3个数求平均值
def average3Number(a,b,c):

    # 因为sum3Number函数已经完成了3个数的就和,所以只需调用即可
    # 即把接收到的3个数,当做实参传递即可
    sumResult = sum3Number(a,b,c)
    aveResult = sumResult/3.0
    return aveResult

# 调用函数,完成对3个数求平均值
result = average3Number(11,2,55)
print("average is %d"%result)

变量作用域

标识符的作用域定义为其声明在程序的可应用范围,或者即是我们所说的变量可见性。换句话说,就好像在问自己,你可以在程序的哪些部分去访问一个制定的标识符。变量可以是局部域或者全局域。

全局变量域局部变量

定义在函数内的变量有局部作用域,在一个模块中最高级别的变量有全局作用域。

“声明适用的程序的范围被称为了声明的作用域。在一个过程中,如果名字在过程的声明之内,它的出现即为过程的局部变量;否则的话,出现即为非局部的”。

全局变量的一个特征是除非被删除掉,否则他们的存在活到脚本运行结束,且对于所有的函数,他们的价值都是可以被访问的,然而局部变量,就像他们存放栈,暂时的存在,仅仅只依赖定义他们的函数现阶段是否处于活动。当一个函数调用出现时,其局部变量就进入声明他们的作用域。在那一刻,一个新的局部变量名为那个对象创建了,一旦函数完成,框架被释放,变量将会离开作用域。

a='foo'
def foo():
	b='bar'
	return a+b
print(foo())
print(a)
print(b)

结果:

Traceback (most recent call last):
foobar
foo
  File "D:\课程所需软件环境指引\pythondemo\py\demo1.py", line 243, in <module>
    print(b)
NameError: name 'b' is not defined
[Finished in 0.2s with exit code 1]

局部变量


def foo():
	a=666
	print('foo(),qian:\t',a)
	a=888
	print('foo(),hou\t',a)

def bar():
	a=6688
	print('bar(),a:\t',a)

结果:

>>>foo()
foo(),qian:	 666
foo(),hou	 888
>>>bar()
bar(),a:	 6688
[Finished in 0.1s]

可以看出:

  • 局部变量,就是在函数内部定义的变量
  • 不同的函数,可以定义相同的名字的局部变量,但是各用个的不会产生影响
  • 局部变量的作用,为了临时保存数据需要在函数中定义变量来进行存储,这就是它的作用

全局变量

同样,先看一下例子:

a=6688
def foo():
	print('foo(),\t',a)

def bar():
	print('bar()\t',a)

print(foo())
print(bar())

运行结果:

foo(),	 6688
None 没有返回值所以输出none
bar()	 6688
None
[Finished in 0.1s]

讨论一:

​ 如果全局变量和局部变量名字相同?

a=6688

def foo():
	a=666
	print('foo()qian\t',a)
	a=888
	print('foo()hou\t',a)

def bar():
	print('bar()\t',a)

foo()
bar()

运行结果为:

foo()qian	 666
foo()hou	 888
bar()	 6688
[Finished in 0.1s]

讨论2:

​ 全局变量,是能够在所有的函数中进行使用的变量,那么局部变量可否进行修改编程全局变量?

globa语句

如果将全局变量的名字声明在一个函数体内的时候,全局变量的名字能被局部变量给覆盖掉。

a=6688
def foo():
	global a

	print('foo()qian\t',a)
	a=666
	print('foo()hou\t',a)

def bar():
	print('bar()\t',a)

foo()
bar()

运行结果:

foo()qian	 6688
foo()hou	 666
bar()	 666
[Finished in 0.1s]

通过以上例子,我们可以观察出:

  • 在函数外边定义的变量叫做全局变量
  • 全局变量能够在所有的函数中进行访问
  • 如果在函数中修改全局变量,那么就需要使用global进行声明,否则出错
  • 如果全局变量的名字和局部变量的名字相同,那么使用的是局部变量的

先举2个例子:

例1:

a=1
def foo():
	a+=1
	print(a)

foo()
当定义全局变量然后赋值是改变了内存地址所有报错
结果:错误的

a=1
def foo():
	global a 全局改变是,需要使用global进行声明
	a+=1
	print(a)

foo()
结果:2

例2:

li=['a','b']
def foo():
	li.append('c')
	print(li)

print(foo())
print(li)
列表是可变的 当改变它的值时内存地址没有发生改变

运行结果:

['a', 'b', 'c']
None
['a', 'b', 'c']
[Finished in 0.1s]

递归函数

递归是颇为高级的话题,它在Python中相对少见。然而,它是一项应该了解的有用的技术,因为它允许程序遍历拥有任意的、不可预知的形状的结构。递归甚至是简单循环和迭代的替换,尽管它不一定是最简单的或最高效的一种。

用递归求和

让我们来看一些例子。

要对一个数字列表(或者其他序列)求和,我们可以使用内置的sum函数,或者自己编写一个更加定制化的版本。这里是用递归编写的一个定制求和函数的示例:

def mysum(L):
	# print(L)
	if not L:
		return 0
	else:
		return L[0]+mysum(L[1:])#调用自身
print(mysum([1,2,3,4,5,6]))

在每一层,这个函数都递归地调用自己来计算列表剩余的值的和,这个和随后加到前面的一项中。当列表变为空的时候,递归循环结束并返回0。当像这样使用递归的时候,对函数调用的每一个打开的层级,在运行时调用堆栈上都有自己的一个函数本地作用域的副本,也就是说,这意味着L在每个层级都是不同的。如上注释部分的print(L),可以运行查看结果。

正如你所看到的,在每个递归层级上,要加和的列表变得越来越小,直到它变为空——递归循环结束。加和随着递归调用的展开而计算出来。

Fibonacci
斐波那契
def a(n):
	if n==1:
		return 1
	if n==2:
		return 1
	else:
		return a(n-1)+a(n-2)
print(a(5))
fin=[]
nn=int(input("请输入n:"))
for i in range(1,nn+1):
	fin.append(a(i))
print(fin)
# f(x)=f(x-1)+f(x-2)

运行结果:

5
请输入n:5
[1, 1, 2, 3, 5]

匿名函数:lambda

lambda表达式

lambda的一般形式是关键字lambda,之后是一个或多个参数(与一个def头部内用括号括起来的参数列表极其相似),紧跟的是一个冒号,之后是一个表达式,即:

lambda para1, para2, ..…, paraN : expression using paras

由lambda表达式所返回的函数对象与由def创建并赋值后的函数对象工作起来是完全一样的,但是1ambda有一些不同之处让其在扮演特定的角色时很有用。

  • lambda是一个表达式,而不是一个语句。因为这一点,lambda能够出现在Python语法不允许def出现的地方——例如,在一个列表常量中或者函数调用的参数中。此外,作为一个表达式,lambda返回了一个值(一个新的函数),可以选择性地赋值给一个变量名。相反,def语句总是得在头部将一个新的函数赋值给一个变量名,而不是将这个函数作为结果返回。

  • lambda的主体是一个单个的表达式,而不是一个代码块。这个lambda的主体简单得就好像放在def主体的return语句中的代码一样。简单地将结果写成一个顺畅的表达式,而不是明确的返回。因为它仅限于表达式,lambda通常要比def功能要小:你仅能够在lambda主体中封装有限的逻辑进去,连if这样的语句都不能够使用。这是有意设计的——它限制了程序的嵌套:lambda是一个为编写简单的函数而设计的,而def用来处理更大的任务。

    除了这些差别,def和lambda都能够做同样种类的工资。例如:

def  add(x,y,z):
	return x+y+z
print(add(1,2,3))
匿名函数
add=lambda x,y,z: x+y+z
#add=f(x,y,z): x+y+z
print(add(1,2,3))

这里是add被赋值给一个lambda表达式创建的函数对象。这也就是def所完成的任务,只不过def赋值是自动进行的。

默认参数也能够在lambda参数中使用,就像在def中使用

f=(lambda a="Tom ",b="loves ",c="python ": a+b+c)
print(f())
print(f('LiLei '))
print(f('Lucy ','likes ','to travel'))
结果:
Tom loves python 
LiLei loves python 
Lucy likes to travel

高阶函数

高阶函数:把一个函数名,以参数的形式,传给这个函数的形参,这个函数就称为高阶函数。

比如下面的形参c,对应的实参是一个函数名abs

# 函数abs() 的功能是取绝对值
def add(a,b,c):
	return c(a)+c(b)

add_value=add(-9,1,abs)
print(add_value)

最正确的高阶函数解释

满足下面两个条件之一,就可称之为高阶函数:

  • 1.把下面函数名当做一个实参,传给另一个函数

  • 2.返回值中包含数名(不修改函数的调用方式)

    例如1:

import time
def bar():
	time.sleep(1)
	print('函数bar')
def test1(func):
	start_time=time.time()
	func()
	stop_time=time.time()
	print("这个函数的运行时间是 %s" %(stop_time-start_time))
test1(bar)
结果:
函数bar
这个函数的运行时间是 1.0006499290466309

例如2:

import time
def bar(): #高阶函数(满足了条件2)
	time.sleep(1)
	print("in the bar")
def test2(func):
	print(func)
	return func
bar=test2(bar)
bar()
结果:
<function bar at 0x0000022BADAC1E18>
in the bar

Python 中常见的高阶函数

(1)filter

  • 功能

    • filter的功能是过滤掉序列中不符合函数条件的元素,当序列中要删减的元素可以用某些函数描述时,就应该想起filter函数。
  • 调用

    • filter(function,sequence),

      • function可以是匿名函数或者自定义函数,它会对后面的sequence序列的每个元素判断是否符合函数条件,返回TURE 或者FALSE,从而只留下TRUE的元素;sequence可以是列表,元组或者字符串。

例子:

x=[1,2,3,4,5]
y=filter(lambda x: x%2==0,x)# 找出偶数
print(y)
<filter object at 0x000001A68B63F0B8>
list(y)#py3之后filter函数返回的不在是列表而是迭代器,所以需要list转换
[2, 4]

奇数
a=[1,2,3,4,5]
def is_add(n):
	return n%2==1
print(list(filter(is_add,a)))

(2)map

  • 功能

    • 求一个序列或者多个序列进行函数映射之后的值,就该想到map这个函数,它是python自带的函数,py3返回的是迭代器,同filter。需要进行进行列表转化
  • 调用

    • map(function,iterable1,iterable2)
      • function中的参数值不一定是一个x,也可以是x和y,甚至多个;后面的iterable表示需要参与function运算中的参数值,有几个参数值就传入几个iterable
x=[1,2,3,4,5]
y=[2,3,4,5,6]
z=map(lambda x, y:(x*y)+2,x,y)
print(z)
print(list(z))
结果:
<map object at 0x000001A75849F128>
[4, 8, 14, 22, 32]

普通方法
def f(x,y):
	return x*y+2
x=[1,2,3,4,5]
y=[2,3,4,5,6]
print(list(map(f,x,y)))
结果:
[4, 8, 14, 22, 32]

(3)reduce

  • 功能

    • 对一个序列进行压缩运行,得一个值。但是reduce在python2的时候是内置函数,到了python3移到了functools,所以使用前需要 from functools inport reduce
  • 调用

    • reduce(function,iterable[, initial])
      • 其中function必须传入连个参数,iterable可以是列表或者元组

例子:

from functools import reduce
y=[2,3,4,5,6]
z=reduce(lambda x,y: x+y,y)
print(z)
结果:
20
from functools import reduce
def f(x,y):
	return x+y
x=[2,3,4,5,6]
print(reduce(f,x))

其计算原理:

先计算头两个元素:f(2, 3),结果为5;

再把结果和第3个元素计算:f(5, 4),结果为9;

再把结果和第4个元素计算:f(9, 5),结果为14;

再把结果和第5个元素计算:f(14, 6),结果为20;

由于没有更多的元素了,计算结束,返回结果20。

(4) apply

  • 功能
    • 是pandas中的函数,应用对象为pandas的DataFrame或者Series。大致有两个方面的功能:一是直接对DataFrame或者Series应用函数,二是对pandas中的groupby之后的聚合对象apply函数
  • 调用
    • apply(function,axis),function表明所使用的函数,axis表明对行或者列做运算

例子:

import numpy as np
import pandas as pd
a=np.random.randint(low=0,high=4,size=(2,4))
print(a)

data=pd.DataFrame(a)
print(data)
print(data.apply(lambda x:x*10))
结果:
[[0 1 3 1]
 [3 1 0 2]]
   0  1  2  3
0  0  1  3  1
1  3  1  0  2
    0   1   2   3
0   0  10  30  10
1  30  10   0  20

(5)zip

  • 功能

    • zip()函数用于将可迭代对象作为参数,将对象中对应的元素打包成一个个元组,然后返回这些元组组成的对象

    • 如果各个迭代对象的元素个数不一致,则返回的对象长度与最短的可迭代对象相同。

    • 利用*号操作符,与zip相反,进行解压。

  • 调用

    • zip(iterable,iterable2,…)
    • iterable——一个或多个迭代对象(字符串,元组,列表,字典)
    • python2中直接返回一个由元组组成的列表,python3中返回的是一个对象,如果想要得到列表,可以用list()函数进行转换.
x=[1,2,3,4,5]
y=[2,3,4,5,6]
print(list(zip(x,y)))
结果:
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]

例子:

a=[1,2,3]  #此处可迭代对象为列表
b=[4,5,6]
c=[4,5,6,7,8]
zipTest=zip(a,b)
print(zipTest)
<zip object at 0x0000000002B76748>#返回的是一个对象
print(list(zipTest))  #转换为列表
[(1, 4), (2, 5), (3, 6)]
print(list(zip(a,c)))
[(1, 4), (2, 5), (3, 6)]
zipT=zip(a,b)
print(list(zip(*zipT)))  #解压也使用list进行转换
[(1, 2, 3), (4, 5, 6)]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值