1.引言
到目前,我们其实对函数已经有一点概念了。比如前面使用过的输入函数input,打印函数print,刚刚操作文件的函数open等。当然,这些都是python给我们已经内置好的函数。本篇文章我们试图搞清楚函数的意义,以及如何自己去定义函数。
如果要给函数下一个定义的话,我们可以这么去描述,即函数是用于封装需要多次,或者说重复执行的代码片段,提高代码的可复用性。这即是函数存在的意义,当然作为面向对象编程语言,函数有更深层次的含义,它是我们组织代码的基本单元之一,于面向对象编程而言,它还起到封装操作的意义。
2.函数
2.1.定义函数
在python中,定义函数通过def关键字进行修饰,函数由函数名称,输入参数,返回值共同组成。具体语法结构:
python
def 函数名称([输入参数]):
函数体
[return 返回值]
2.2.调用函数
定义函数,以及调用函数
python
# 定义函数
def hello_fun(name):
print(f"hello {name}!")
return "ok"
# 调用函数
result = hello_fun("python")
print(result)
2.3.匿名函数
匿名函数是通过lambda表达式进行函数的定义和调用。基本语法:
python
# 定义匿名函数
square = lambda x: x**2
#调用匿名函数
print(square(5))
2.4.高阶函数
python中,函数可以作为对象来使用,像这样:
python
# 定义一个函数
def add(x):
return x+x
# 调用函数
sum = add(1)
print(sum)
#函数作为对象来使用
add_2 = add
print(add_2(1))
将函数作为对象来使用有什么好处?解决了什么问题?答案常见场景下,用于配合高阶函数来使用,让代码更优雅简洁!
什么是高阶函数?可以接收函数作为参数传入的函数,叫做高阶函数。python典型的高阶函数有:map,filter,sorted,reduce。
2.4.1.高阶函数map
map映射函数,示例:
python
# 高阶函数map
list = [1,2,3,4,5,6]
for i in map(add,list):
print(i)
将可迭代对象list中的每个值,作用于add函数,当然具体业务需求要做什么,取决于add函数怎么定义了。
2.4.2.高阶函数filter
filter过滤函数,示例:
python
# filter 过滤函数
list = [1,2,3,4,5,6]
for i in filter(lambda x:x%2==0,list):
print(i)
2.4.3.高阶函数sorted
sorted排序函数,示例:
python
# sorted 排序函数
list = [1,2,3,4,5,6]
for i in sorted(list,key=lambda x:-x):
print(i)
2.4.4.高阶函数reduce
累积求值函数reduce,函数:
python
from functools import reduce
# reduce 累积求值函数
list = [1,2,3,4,5,6]
print(reduce(lambda x,y:x+y,list))
注意:reduce函数已经移入functools模块,使用要先导入。关于import知识后面会详细说明。
2.5.偏函数
python中偏函数,指的是可以用于将已有函数,和参数固化成为新的函数来使用。说概念有点绕,看一个示例就明白了:
python
# 操作文件open函数,有太多参数了,又是mode,又是encoding,每次传值其实都是一样的。像这样
with open("hello.txt","r",encoding="utf-8") as f:
#读取文件内容
data = f.read()
print(data)
有没有什么方法简化一下open函数的使用?可以这样:
python
# 固化一下open函数及参数,方便使用
from functools import partial
my_open = partial(open,mode='r',encoding='utf-8')
with my_open("hello.txt") as f:
data = f.read()
print(data)
2.6.装饰器
python中装饰器具有强大的语法特性,允许在不修改原函数或原类的代码前提下,动态的增强功能。这不类似代理吗?与spring框架中的AOP一个道理。装饰器的核心价值点在于代码复用,和关注点分离。
所以,我们常说万变不离其宗,很多东西表象(不同编程语言实现语法)不一样,但本质其实是一样的。在python中语法层面在具体一点描述装饰器,它是一个可调用对象,这里可调用对象指:函数或者类。其本质接收一个函数作为输入,返回新函数。
2.6.1.装饰器应用场景
在实际应用中,装饰器所解决的问题域有:
- 日志记录:自动记录函数调用信息
- 执行耗时统计:统计函数执行时间
- 权限校验:检查校验用户操作权限
- 缓存:缓存函数结果
- 路由注册:Flask这样的web框架,通过装饰器注册url
2.6.2.闭包
要搞清楚装饰器的运用,需要先理解闭包的概念,闭包其实就是函数嵌套。示例:
python
# 闭包,定义函数嵌套
def my_out():
num = 50
# 函数内部再定义函数
def my_in():
return num
#返回内部定义函数
return my_in
# 直接调用函数
print(my_out()())
# 通过中间形式调用函数
f = my_out()
print(f())
2.6.3.简单装饰器示例
直观感受一个装饰器示例:
python
def my_decorator(func):
def wrapper():
print("函数执行前")
# 调用原函数
func()
print("函数执行后")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
2.6.4.带参数装饰器
装饰器本身可以有参数,像这样:
python
# 外层接收装饰器参数
def repeat(n):
# 中层接收被装饰函数
def decorator(func):
# 内层包装原函数
def wrapper(*args, **kwargs):
for _ in range(n):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(3)
def greet(name):
print(f"Hello, {name}!")
greet("小明")
2.6.5.保留原函数元信息
装饰器会导致原函数的 __name__
等元信息丢失,使用 functools.wraps
解决 。像这样:
python
from functools import wraps
def log_decorator(func):
# 保留原函数元信息
@wraps(func)
def wrapper(*args, **kwargs):
print(f"调用函数: {func.__name__}")
return func(*args, **kwargs)
return wrapper
@log_decorator
def example():
"""函数文档定义"""
pass
print(example.__name__)
print(example.__doc__)
2.6.6.类装饰器
除了函数实现装饰器,类同样可以作为装饰器。像这样:
python
import time
# 定义Timer类,通过__call__实现装饰器功能
class Timer:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
import time
start = time.time()
result = self.func(*args, **kwargs)
end = time.time()
print(f"耗时: {end - start:.2f}秒")
return result
@Timer
def slow_function():
time.sleep(1)
slow_function()