一、什么是函数
函数是一段可以重复使用的代码块,用于执行特定的任务。函数将输入数据(参数)作为输入,通过代码处理后,返回输出结果。函数可以帮助组织代码,减少重复,提高代码的可读性和维护性。
函数使用def关键字定义函数:
def function_name(parameters):
"""
Optional docstring
"""
Function body
return value
function_name:函数的名称。
#parameters:函数的输入参数,可以有多个,也可以没有。
return:函数返回的值。如果没有return语句,函数默认返回None。
实例:
def greet(name):
print(f"Hello, {name}!")
greet("nb")
输出:Hello, nb!
参数类型
位置参数:传递给函数的参数,按着函数定义的顺序匹配。
def add(a, b):
return a + b
print(add(2, 3)) 输出:5
默认参数:为参数提供默认值,如果调用时没有提供这些参数的值,函数将使用默认值。
def greet(name="wwn"):
print(f"Hello, {name}!")
greet()
greet("nb")
输出 Hello, wwn!
Hello, nb!
关键字参数: 通过参数名称来传递参数值,这样可以在调用时更清晰地指定参数。
def describberbe_me(name, age, city):
print(f"My name is {name}, I am {age} years old, and I live in {city}.")
describberbe_me("wwn", 25, "Beijing")
输出:My name is wwn, I am 25 years old, and I live in Beijing.
不定长参数:用于接收可变数量的位置参数或关键字参数
1)*args:接收任意数量的位置参数,作为一个元组
def connect(*args):
return "-".join(args)
print(connect("qqq", "nb", "hs"))
输出 qqq-nb-hs
def add(*args):
return args0 + args1
print(add(2, 3))
*args 会将传递给函数的多个位置参数收集起来,形成一个元组。在函数中, '-'.join(args) 方法会将这些参数用空格 ' ' 连接成一个字符串。比如传递 "qqq", "nb", "hs"函数会将它们组合成 qqq-nb-hs。
传入2,3 组成一个元组 (2,3) 在 Python 里,元组就是一组有序、不能修改的数据集合 ,用小括号
()包裹。这个等于是 2+3 输出:5
2)**kwargs:接收任意数量的关键字参数,作为一个字典。
def connect(**kwargs):
return "-".join(kwargs.values())
print(connect(a="qqq", b="nb", c="hs"))
输出:qqq-nb-hs
def printer(**kwargs):
for key, value in kwargs.items():
print(f"{key} is {value}")
printer(name="qqq", age=25, city="Beijing")
输出:name is qqq
age is 25
city is Beijing
**kwargs 会 将 传 递 的 关 键 字 参 数 收 集 成 一 个 字 典 。 在 函 数 中 , kwargs.items() 方法返回字典中的键值对,并允许我们遍历每一个键值对。
函数的嵌套和作用域
函数的嵌套
函数可以在其他函数内部定义,这叫做嵌套函数。内部函数可以访问外部函数的变量,但外部函数不能直接访问内部函数。
def outer_function(x):
def inner_function(y):
return y +2
return inner_function(x) + 5
print(outer_function(3))
输出:10
作用域
x = 20
def modify_global():
global x
x = 30
modify_global()
print(x)
输出30
定义了一个全局变量 x,并将其初始化为 10。这个变量 x 可以在程 序的任何地方被访问和修改。
global 关键字的作用:当你在函数内部想要修改一个全局变量时,你需要告诉 Python 你是在修改全局变量,而不是创建一个新的局部变量。这个时候就需要使用 global 关键字。
global 只会改变【函数执行之后】的 x, 不会改变【函数执行之前】的 x。
高阶函数
高阶函数的一个关键特点是它们可以接受其他函数作为参数。通过将函数作为参数传递, 你可以在不同的场景下复用代码,并使代码更具灵活性。
函数作为参数
def apply_func(func,value):
return func(value)
def square(x):
return x * x
result = apply_func(square, 5)
print(result)
1.apply_function 是一个高阶函数,它接受两个参数:
func 是一个函数。
value 是一个任意类型的值。
2.apply_function 的内部逻辑非常简单:它调用 func,并将 value 作为参数传递给 func,然后返回 func(value) 的结果。
3.square 是一个简单的函数,它计算传入参数的平方。
4.当你调用 apply_function(square, 5) 时,实际上是将 square 函数和数值 5 传递给了 apply_function。在 apply_function 内部,square(5) 被计算,结果是 25,并返回该结果。
展示了如何将一个函数作为参数传递给另一个函数,从而让 apply_function 函数可以处理任意类型的操作,而不仅仅是平方计算。
返回函数
高阶函数的另一个特点是它们可以返回函数。这使得你可以创建"定制化"的函数,根据不同的上下文返回不同的行为。
def make_multiplier(multiplier):
def multiplier_func(x):
return x * multiplier
return multiplier_func
double = make_multiplier(2)
result = double(5)
print(result)
代码解释:
make_multiplier 是一个高阶函数:
高阶函数是指接受一个或多个函数作为参数,或返回一个函数的函数。
make_multiplier 这个函数接受一个参数 multiplier,但它的返回值是一个函数,而不是具体的数值。
内部嵌套函数 multiplier_function:
在 make_multiplier 函数内部,定义了一个函数 multiplier_function,这个函数接受一个参数 value。
multiplier_function 的作用是将 value 与 multiplier 相乘,并返回这个结果。注意,multiplier 是在外部函数 make_multiplier 中定义的。
返回 multiplier_function:
make_multiplier 并没有直接返回计算结果,而是返回了 multiplier_function 这个函数本身。
这意味着,调用 make_multiplier 后,返回的是一个新的函数,这个函数可以记住调用 make_multiplier 时传入的 multiplier 值。
调用 make_multiplier(2):
当调用 make_multiplier(2) 时,它生成了一个专门用于将数值乘以 2 的函数,并将这个函数赋值给 double。
此时,double 变量是一个函数,它记住了 multiplier 值为 2。 使用 double(5):
当你调用 double(5)
其实就是调用 multiplier_function(5),函数内部会将 5 乘以之前传入的 multiplier 值 2,所以结果为 10。
总结:
这个示例展示了如何使用一个高阶函数生成不同功能的函数。通过返回一个"定制化"的函数(如乘以 2、乘以 3 等),可以让代码更加灵活。
这种方式通过闭包机制实现了数据的"记忆",即返回的函数能够访问其外部作用域的变量 multiplier,提高了代码的复用性和灵活性。
实战案例
1、命令执行器
def make_command(server_name):
def command(command_name):
return f"ssh {server_name} {command_name}"
return command
server1 = make_command("server1")
server2 = make_command("server2")
result1 = server1("ls")
result2 = server2("pwd")
print(result1)
print(result2)
输出:
ssh server1 ls
ssh server2 pwd
2、自动化任务调度
经常需要对不同服务器执行相似的任务,如备份数据库、清理临时文件等。我们可以使用高阶函数来创建动态的任务调度器,根据不同服务器的配置来定制执行任务的策略。
def task(task):
def backup():
print(f"Backing up {task}")
def cleanup():
print(f"Cleaning up {task}")
def report():
print(f"Reporting on {task}")
if task == "backup":
return backup
elif task == "cleanup":
return cleanup
elif task == "report":
return report
else:
print("Invalid task")
daily_backup = task("backup")
daily_cleanup = task("cleanup")
daily_report = task("report")
daily_backup()
daily_cleanup()
daily_report()
3、动态配置生成器
在配置管理中,不同环境(如开发、测试、生产)需要不同的配置文件。我们可以通过高阶函数生成适用于不同环境的配置生成器,从而简化管理和部署过程。
def make_config(env):
def prod_env():
return("Production environment")
def dev_env():
return("Development environment")
def test_env():
return("Test environment")
if env == "prod":
return prod_env
elif env == "dev":
return dev_env
elif env == "test":
return test_env
else:
print("Invalid environment")
prod_config = make_config("prod")
prod_config()
print(prod_config())
4、动态日志分析器
需求:设计一个通用的日志解析器,用于解析不同类型服务的日志(如Nginx日志和系统messages日志)
编写动态解析器生成函数
编写一个make_log 函数,该函数可以根据传入的服务名动态返回一个专门用于该服务的解析器。
这样设计的目的是为了实现代码复用和简化扩展:未来如果需要添加新的日志类型,只需在函数内扩展。
import sys
import io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
import re
def make_log(service_name):
def nginx_log(line):
parts = line.split()
return {
'ip': parts0, # 获取客户端 IP 地址
'date': parts31: + ' ' + parts4:-1, # 提取日期和时间,去除方括号
'request': ' '.join(parts5:8), # 获取请求方法和路径及 HTTP 协议
'status': parts8, # 获取 HTTP 状态码
'size': parts9, # 获取返回内容的大小
'referrer': parts10, # 获取请求来源
'user_agent': ' '.join(parts11:).strip(' "').strip() # 获取用户代理,去除前后的引号
}
def messages_log(line):
parts = line.split()
return {
'date': parts0 + parts1 + parts2, # 提取日期和时间
'host': parts3, # 提取主机名
'service': parts4.split('')\[0, # 提取服务名
'pid': parts4.split('')\[1.split(']')0, # 提取进程 ID
'message': ' '.join(parts5:) # 提取消息内容
}
if service_name == 'nginx':
return nginx_log
elif service_name == 'messages':
return messages_log
else:
raise ValueError("Invalid service name")
使用示例
nginx_log = '192.168.40.80 - - 30/Aug/2030:11:27:18 +0800 "GET / HTTP/1.1" 200 3429 "-" "curl/7.61.1" "-"'
print(make_log('nginx')(nginx_log))
messages_log = 'Aug 30 18:08 myhost sshd1234: Accepted password for user from 192.168.1.2 port 22 ssh2'
print(make_log('messages')(messages_log))
输出:
{'ip': '192.168.40.80', 'date': '30/Aug/2030:11:27:18 +0800', 'request': '"GET / HTTP/1.1"', 'status': '200', 'size': '3429', 'referrer': '"-"', 'user_agent': 'curl/7.61.1" "-'}
{'date': 'Aug3018:08', 'host': 'myhost', 'service': 'sshd', 'pid': '1234', 'message': 'Accepted password for user from 192.168.1.2 port 22 ssh2'}