0%

Python编程—函数

使用def定义函数是Python程序的基础,本文主要记录Python中函数定义与使用,包括函数参数,装饰器,生成器和迭代器等相关内容。

1. 函数定义

Python中定义函数使用关键字def,一般格式如下:

1
2
3
def func_name(args):
statement_block
return value

2. 函数参数

Python中函数可使用的参数类型有:

  • 普通参数:普通参数必须以正确的顺序传入函数,调用时的数量必须和声明时一样。
  • 默认参数:默认参数是指在函数定义时,给该参数指定了一个默认值。调用函数时,如果没有传入该参数的指定值就使用默认值。默认参数必须在非默认参数之后
  • 关键参数:在函数调用时指定了参数名的参数就叫关键参数。正常情况下,给函数传递参数要按顺序,关键参数可以不按顺序,但是关键参数必须放在普通参数之后,即关键参数之后的参数必须以关键参数的形式出现。
  • 非固定参数:函数定义时不确定传入的参数个数,就可以使用非固定参数。非固定参数必须放在普通参数之后定义。

    非固定参数:非固定参数通过*操作符来进行表示

    • *args:元组类型的非固定参数,即参数以元组的形式导入
    • **args:字典类型的非固定参数,即参数以字典的形式导入

    NOTE:定义函数时,*可以单独出现,但是单独出现的*之后的参数必须用关键参数传入。

    1
    2
    3
    4
    5
    def student(name, age,*args,**kwargs):
    print(name, age,args,kwargs)

    stu = student('lihua',25,'cpp','python',gender='male',country='CN')
    # 输出:lihua 25 ('cpp', 'python') {'gender': 'male', 'country': 'CN'}

3. 参数传递

Python中数据类型分为可变和不可变,因此函数的参数传递也分为传递可变对象和传递不可变对象:

  • 传递不可变对象:类似于C++的值传递
  • 传递可变对象:类似于C++的引用传递

4. 匿名函数

匿名函数就是不需要通过def显式的指定函数名的函数,Python中使用lambda来创建匿名函数。
lambda函数的一般格式如下:

1
lambda [arg1[,arg2,...,argn]]:statement_block

NOTE:

  • lambda只是一个表达式,函数体简单,只能封装简单的逻辑语句
  • lambda有自己的命名空间,只能访问参数列表中的函数
  • lambda只能写一行语句

5. 迭代器与生成器

5.1 迭代器

迭代器是一种可以将可迭代对象(如列表,元组,字典等)循环输出的工具。迭代器从集合的第一个元素开始访问,直到所有元素访问结束。迭代器有两个基本的方法:iter()next()iter()函数可以将可迭代对象转为迭代器,迭代器可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration异常
NOTE:

  • 可迭代对象:可以直接作用于for循环的对象统称为可迭代对象,可以通过isinstance(obj,Iterable)判断一个对象是否是可迭代对象
  • 可作用于next()函数的对象都是迭代器
  • StopIteration异常用于标识迭代的完成,防止无限循环的情况

5.2 生成器

在Python中,包含了yield关键字的函数被称为生成器。与普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,即生成器就是一个迭代器。
在调用生成器运行的过程中,每次遇到yield时函数会暂停保存当前所有的运行信息,返回yield的值,并在下一次执行next()函数时从当前位置继续运行。
yield可以理解成一个特殊的returnreturn返回的是一个值,下次调用该函数时重新开始,yield返回的是一个生成器,下次调用函数会继续从上一次yield后的地方继续运行。

6. 函数装饰器

通常情况下,需要对现有的函数增加新的功能,应该遵循开放封闭原则,即已经实现的代码修改封闭,对功能扩展开放。装饰器的作用就是在不修改原函数的情况下添加新的功能

Note:函数装饰器用到的知识点:

  • 在Python中,函数也是一个对象
    1
    2
    3
    4
    def student(name, age):
    print(name, age)
    stu = student # 此时函数没有小括号,并不是在调用函数,而是将函数对象赋值给一个变量
    stu('lihua',25) # 输出:lihua 25
  • 可以在函数中定义另外的函数,即进行函数嵌套
  • 函数对象可以作为返回输出,也可以作为参数传递给另外一个函数
  • @语法糖,放在函数开始定义的地方,可以省略最后一步再次赋值的操作

为了实现在不修改原函数的情况下添加新的功能,装饰器将原函数作为参数传递到装饰器函数中,装饰器函数中定义了一个嵌套函数来对原函数进行功能扩充,并在装饰器函数中将嵌套函数对象作为返回值进行返回。装饰器相当于高阶函数(将函数作为参数)和嵌套函数的结合,其依然是函数。装饰器的一般格式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def 装饰器函数(传入的函数):
def 执行的嵌套函数(传入函数的参数):
装饰器语句
...
传入的函数(传入函数的参数)
...
装饰器语句

return 返回的嵌套函数

@装饰器函数
def 原函数(args):
原函数体

6.1 装饰器执行流程

  • 执行装饰器函数,并将原函数作为参数传递给装饰器函数
  • 装饰器函数执行完毕之后将嵌套函数对象赋值给原函数的函数名,即原函数被更新替换成了嵌套函数

6.2 functools.wraps

装饰器内的函数替代了原函数,但是原函数的元信息没有被赋值装饰器函数内部,可以通过使用@functools.wraps装饰修饰器内的函数,就可以将原函数的属性值赋值给装饰器函数。

1
2
3
4
5
def wrapper(func):
@functools.wraps(func)
def inner(*args,**kwargs):
pass
return inner

参考文献 & 资源链接