目录
引言
在前面的文章中,已经提过,所谓编程,核心内容只有两块:数据的表示、数据的处理。数据的表示可以通过各种基本类型、容器类型的组合来实现;数据的处理,就是在顺序、循环、分支的框架下,对数据结构进行不断重新赋值。
刚开始学习编程的新手,似乎不太习惯使用用户自定义函数(User Defined Function, UDF)来编写数据的处理功能。习惯于在脚本中按顺序进行语句与表达式的堆砌。
如果数据处理的逻辑表简单的话,不使用函数也是可以的,毕竟够用就好。但是,如果数据处理的逻辑比较复杂的话,还是使用代码一行行堆积来实现功能,就不太合适了……
可以想象一下,要从一坨几百行、几千行、甚至更多行的代码中读懂处理逻辑,然后还要进行修改、扩充。单单只是读,可能都要吐了。
程序员最怕的有两件事:1)读别人的代码;2)读自己的代码。
所以,为了避免日后自己看吐或者把别人看吐,UDF还是需要学一下的。
函数的好处
Python程序员首先应该考虑的代码整理工具就是函数(function)。与其他编程语言一样,Python的函数也可以把大段程序分解为多个小块儿,并且用直观的名字表示每块儿代码的用途。这样可以让代码更好理解,也更容易复用与重构。
简单梳理一下,在编程中,使用函数的好处有如下:
- 代码的复用:一次定义,多次调用。
- 提高代码的可维护性:代码复用的情况下,一次修改,多处生效。
- 逻辑分离与模块化:代码不再是一整坨,而是一块块的。
- 提高代码的可读性:代码逻辑分离与模块化之后,自然更加易读、易于维护。
- 提高可扩展性:使用函数,可以更加容易进行功能的添加、或者修改。
- 易于调试:模块化的好处,可以各自独立进行功能的调试,快速定位到问题。
函数的基本用法
编程语言中的函数概念,可以类比于数学中的函数的概念。函数的用途在于对数据进行处理,所以,通常需要有输入数据、数据处理逻辑、和输出数据。
在Python中自定义一个函数,可以如下操作:
def my_sum(a, b):
"""
计算两个数的和,并返回
:param a:
:param b:
:return: a + b
"""
return a + b
可以大概看到一个函数的构成,主要包含:
- def关键字:用于定义函数。
- 函数头:函数名(参数列表),参数列表可以为空。
- docstring:函数的说明文档,以三个引号括起来的字符串,可以没有,如果有,需要放在行数体内的第一行。
- 函数体:数据的处理逻辑代码。
- 返回值:使用return语句将要输出的数据进行返回,可以没有,没有的话,就是返回None。
以上只是一个函数的定义,要把函数的功能用起来,需要对函数进行调用:
result = my_sum(10, 20)
print(result)
调用函数非常简单,只需要将参数对应传入即可。
通过赋值语句接收函数的返回值。
参数默认值的用法
Python支持在函数的定义过程中,给部分参数设置默认值,从而支持当默认情况满足需求的情况下,减少参数个数的传递,从而更加便于使用。而且,可以通过参数默认值,增加函数的灵活性。
比如:登录用户,能够获取到用户名,如果未登录用户,则以‘游客’来称呼:
def greet(username='游客'):
return f"{username},您好,欢迎使用XXX系统"
print(greet())
print(greet('南宫理'))
执行结果:
需要注意的是,带默认值的参数,只能出现在参数列表的最后,可以是多个,否则会报语法错误。
这个语法规定,应该很好理解,如果你是Python解释器,你怎么处理带默认值的参数,才能不会出现二义性呢。
lambda函数(匿名函数)
本着能用一行代码解决的事情,绝不写第二行的理念。有些情况下,使用def定义函数,有点繁琐了……
好在Python提供了lambda函数的支持。
lambda函数一种匿名函数,可以实现在一行代码中定义一个功能相对简单的函数。直接上代码:
my_sum = lambda a, b: a + b
result = my_sum(10, 20)
print(result)
greet = lambda username='游客': f'{username},您好,欢迎使用XXX系统'
print(greet())
print(greet('南宫理'))
前面两个简单函数的lambda实现,确实少了一行代码。
但是,其实lambda函数,更多地应用于将函数作为参数传递的场景,比如,当我们使用内置函数sorted()时,先看下sorted()函数的说明文档:
函数中有个key参数,用于传递一个表示排序规则的函数,函数返回一个新的list,包含排序之后的数据,而不会修改原来的对象。
此外,sorted函数还有一个带默认值的参数reverse=False,表示默认按照升序排列。
以一个关于成绩排序的场景,来简单使用一下该函数:
from faker import Faker
# 从rich模块导入print,覆盖builtins中的print
from rich import print
from rich.console import Console
console = Console()
fk = Faker('zh_CN')
# 生成测试数据,姓名,语文成绩、数学成绩、英语成绩
scores = [{'name': fk.name(), 'chinese': fk.random_int(0, 100), 'math': fk.random_int(0, 100),
'english': fk.random_int(0, 100)} for i in range(5)]
def get_chinese(score):
return score['chinese']
scores_sort_by_chinese = sorted(scores, key=get_chinese)
console.rule('排序前')
print(scores)
console.rule('排序后')
print(scores_sort_by_chinese)
执行结果:
这里,定义了一个get_chinese()的函数,作为key的参数。由于排序的规则比较简单,更适合使用lambda函数。
from faker import Faker
# 从rich模块导入print,覆盖builtins中的print
from rich import print
from rich.console import Console
console = Console()
fk = Faker('zh_CN')
# 生成测试数据,姓名,语文成绩、数学成绩、英语成绩
scores = [{'name': fk.name(), 'chinese': fk.random_int(0, 100), 'math': fk.random_int(0, 100),
'english': fk.random_int(0, 100)} for i in range(5)]
scores_sort_by_chinese = sorted(scores, key=lambda score: score['chinese'])
scores_sort_by_math = sorted(scores, key=lambda score: score['math'], reverse=True)
scores_sort_by_english = sorted(scores, key=lambda score: score['english'], reverse=True)
console.rule('排序前')
print(scores)
console.rule('按语文成绩升序排序')
print(scores_sort_by_chinese)
console.rule('按数学成绩降序排序')
print(scores_sort_by_math)
console.rule('按英语成绩降序排序')
print(scores_sort_by_english)
执行结果:
总结
由于篇幅所限,这篇文章只介绍了关于函数的优点,以及函数的一些基础用法。最后在介绍lambda函数的时候,以一个简单的实际案例做了演示。案例中用到的rich和faker第三方框架,在前面的文章中已经介绍过,为了便于不熟悉的小伙伴学习使用,省去到故纸堆里搜检的工作,我把链接附在文章末尾。