python函数详解(定义、参数、返回值、高级函数、偏函数、装饰器)
一.说明
这是python中的基础系列中的关于函数部分,来开始我们今天日拱一卒!对python函数部分进行详细整理和学习。
二.定义
-
在Python中,函数是通过
def
关键字来定义函数; -
函数定义的结构如下
def function_name(parameters):"""函数的文档字符串,可选"""# 函数体return value # 可选
-
function_name
是函数的名称,遵循标识符命名规则 -
parameters
是函数的输入参数,可以有多个,也可以没有 -
函数体是实现具体功能的代码块
-
return语句用于返回结果,若没有,则默认返回 None
三.特性
- 封装性:函数将特定功能的代码封装在一起,便于复用
- 可读性:通过函数名称和文档字符串,提升代码的可读性
- 模块化:可以将复杂的任务分解为多个简单的函数,便于管理和调试
四.函数参数
在各类语言中函数参数一般都分为形参和实参!这个概念,很多时候被忽略,因为就算不理解这一概念,也照样使用,那么什么是形参和实参,很简单,让我来概括。
形参:函数定义是的参数就是形参;
实参:函数调用时传入的参数就是实参;
就这么简单?在python中这一概念可不这么简单!!让我来细细整理,这是核心!!
1.位置参数
参数的定义和调用,按顺序传递
def greet(name):print(f"Hello, {name}!")
greet("Alice") # 输出: Hello, Alice!
2.关键字参数
调用时,通过参数名称传递
def greet(name, age):print(f"{name} is {age} years old.")
greet(age=30, name="Bob") # 输出: Bob is 30 years old.
3.默认参数
可以为参数指定默认值,注意,这里又有一个隐藏概念!指定默认值的行参必须放在未指定默认值的形参后面
def greet(name, greeting="Hello"):print(f"{greeting}, {name}!")
greet("Alice") # 输出: Hello, Alice!########
def greet(greeting="Hello",name):print(f"{greeting}, {name}!") #报错
greet("Alice")
4.可变参数
使用 *args
和 **kwargs
处理不定数量的参数
*args
:传入参数被当作元组处理
**kwargs
:传入参数被当作字典处理
def summarize(*args):return sum(args)def show_info(**kwargs):for key, value in kwargs.items():print(f"{key}: {value}")summarize(1, 2, 3) # 输出: 6
show_info(name="Alice", age=30) # 输出: name: Alice, age: 30
可变参数 是不是觉得很简单,一看就会?等会一练就废!大家看看下面的代码,输出结果是什么?
def demo(a,b,*args):print("a:",a)print("b:",b)print("arg:",args)
demo(1,2,3)
demo(1,2,3,4,5)def demo1(a,**args):print("a",a)print("args",args)
demo1(1,name='bob',age=33)def demo3(a,b,c=0,*args,**kwargs):print("a:",a)print("b:",b)print("c:",c)print("arg:",args)print("kwargs:",kwargs)demo3(1,2,k=3)
demo3(1,2,3,4,5)
demo3(1,b=2,c=3,d=4)
demo3(*(1,2,3),**{'age':4}) def custom_function(a, b, c=0, *args, **kwargs):print("a:", a)print("b:", b)print("c:", c)print("args:", args)print("kwargs:", kwargs)custom_function(1, 2)
custom_function(3, 4, 5, 6, 7, name="Alice")
5.函数参数默认值计算方式
先看一下这个案例:
def test(a=[]):a.append('end')print(a)
test([1,2,3]) #[1,2,3,'end']
test() #['end']
test() #['end','end']
test([4,5,6]) #[4,5,6,'end']
请问为啥会出现[‘end’,‘end’]?为什么会出现这种情况!
这个与python语言特性和 python中函数的参数默认值实现逻辑有关!
函数参数的默认值只在函数定义时计算一次,而不是每次调用时,这意味着如果你使用可变对象(如列表或字典)作为默认值,它会在后续调用中保持修改状态。
好那么还有一个疑问,如何避免这个问题?
def test(a=None):if a is None:a = []a.append('end')print(a)
五.返回值
-
return 语句返回 函数的计算结果,也可以没有return 默认返回 None
def demo1():passa = demo1() print(a) #None
-
return 可以返回一个值,也可返回多个值,当返回多个值 那么返回的是一个元组
def demo1():return 1,2,3,4a = demo1() print(a) #(1, 2, 3, 4)
六.文档字符串
函数的文档字符串,其实就是函数的帮助文档,包含函数的基础信息、函数的功能简介、函数的形参类型,使用等
文档字符串规则:
-
必须在函数首行定义文档字符串;
-
使用三个引号 注解;
#Google 风格
def multiply(x, y):"""Multiply two numbers.Args:x (int or float): The first number.y (int or float): The second number.Returns:int or float: The product of x and y."""return x * y#NumPy 风格
def divide(x, y):"""Divide x by y.Parameters----------x : int or floatThe numerator.y : int or floatThe denominator.Returns-------floatThe result of x divided by y."""return x / y
七.函数的类型
-
空函数
函数体不完成任何功能,只有一个pass
def demo1():passa = demo1() print(a) #None
-
匿名函数
不再使用def 函数名()这种形式定义函数,而是使用lambda来创建匿名函数
lambda函数:
-
lambda 函数只能包含一个表达式,即只有一行,不能包含多个语句或复杂逻辑
-
lambda函数是匿名的,但可以将其赋值给一个变量,以便后续使用
add = lambda x, y: x + y print(add(3, 5)) # 输出: 8#过滤 numbers = [1, 2, 3, 4, 5, 6] even_numbers = list(filter(lambda x: x % 2 == 0, numbers)) print(even_numbers) # 输出: [2, 4, 6] #映射 squared_numbers = list(map(lambda x: x ** 2, numbers)) print(squared_numbers) # 输出: [1, 4, 9, 16, 25, 36] #排序 people = [{'name': 'Alice', 'age': 30},{'name': 'Bob', 'age': 25},{'name': 'Charlie', 'age': 35} ]# 按年龄排序 sorted_people = sorted(people, key=lambda person: person['age']) print(sorted_people) # 输出: [{'name': 'Bob', 'age': 25}, {'name': 'Alice', 'age': 30}, {'name': 'Charlie', 'age': 35}]
八.高级函数
高阶函数是指可以接受其他函数作为参数或返回一个函数的函数
def high_order_function(func):return func(10)def square(x):return x * xresult = high_order_function(square) # 输出: 100
print(result)
九.偏函数
偏函数(Partial Function)是指通过固定一个函数的部分参数来创建一个新的函数。在Python中,可以使用 functools
模块中的 partial()
函数来实现偏函数。这种方式特别有用,可以使函数更加灵活和简洁。
from functools import partialdef calculate_price(original_price, discount_rate):"""计算折后价格"""return original_price * (1 - discount_rate)# 固定折扣率为 20%
calculate_discounted_price = partial(calculate_price, discount_rate=0.20)# 示例商品价格
prices = [100, 200, 300, 400]# 计算折后价格
discounted_prices = [calculate_discounted_price(price) for price in prices]# 打印结果
for original, discounted in zip(prices, discounted_prices):print(f"原价: {original},折后价: {discounted:.2f}")'''
原价: 100,折后价: 80.00
原价: 200,折后价: 160.00
原价: 300,折后价: 240.00
原价: 400,折后价: 320.00
'''
十.装饰器
这个为函数这一概念中的重点的重点,在现实开发中使用场景非常多,想学习python必须掌握装饰器,这一概念!不然根本不算入门!
当然学习函数装饰器也很简单,静下来,看完慢慢缕一缕!
-
概念
装饰器本质上是一个函数,它接受另一个函数作为参数,并返回一个新的函数。这个新的函数通常是在原始函数的基础上,增加了一些额外的功能。
-
装饰器语法
装饰器使用
@decorator_name
语法来应用于函数。下面是一个简单的示例:def my_decorator(func):def wrapper():print("Something is happening before the function is called.")func()print("Something is happening after the function is called.")return wrapper @my_decorator def say_hello():print("Hello!") #调用 say_hellosay_hello()''' 输出:Something is happening before the function is called. Hello! Something is happening after the function is called. '''
- 定义装饰器:
my_decorator
是装饰器,它接受一个函数func
作为参数。wrapper
是内部函数,执行装饰器的额外逻辑,调用原始函数func
。
- 使用装饰器:
@my_decorator
将say_hello
函数传递给my_decorator
。say_hello
实际上变成了wrapper
函数。
- 调用函数:
- 当你调用
say_hello()
时,实际上是在调用wrapper()
。
- 当你调用
- 定义装饰器:
-
带参数装饰器
如果你想要装饰器接受参数,可以通过定义一个装饰器工厂来实现:
def repeat(num_times):def decorator_repeat(func):def wrapper(*args, **kwargs):for _ in range(num_times):func(*args, **kwargs)return wrapperreturn decorator_repeat @repeat(3) def greet(name): print(f"Hello, {name}!") greet("Alice")''' 输出: Hello, Alice! Hello, Alice! Hello, Alice! '''
-
使用场景
- 日志记录:在函数执行前后记录日志
- 权限验证:检查用户是否有权调用某个函数
- 缓存:存储函数结果以减少计算时间
-
保持原函数的元数据
使用
functools.wraps
可以确保装饰器不会丢失原函数的元数据(如名称和文档字符串)from functools import wraps def my_decorator(func): @wraps(func) def wrapper(): print("Before") func() print("After") return wrapper
-
总结
装饰器是一个非常强大的特性,可以在不修改函数本身的情况下,增加或改变其行为。它们在许多框架和库中被广泛使用,例如 Flask 和 Django,常用于路由、请求处理和权限控制。。
其实要掌握也很简单,照抄写法就行 主要是带参数的装饰器。。
十一.总结
其实函数还有一大模块,变量和作用域,这一概念需要单独提出来写,函数这一概念 重点注意 参数传递/调用/返回值/装饰器,特别是装饰器 这东西实在太强大了,相比其他语言想要实现这一功能就要复杂很多!
创作整理不易,请大家多多关注 多多点赞,有写的不对的地方欢迎大家补充,我来整理,再次感谢!