python-14-函数详解(定义、参数、返回值、高级函数、偏函数、装饰器)

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)

'''

a: 1

b: 2

arg: (3,)

a: 1

b: 2

arg: (3, 4, 5)

'''

def demo1(a,**args):

print("a",a)

print("args",args)

demo1(1,name='bob',age=33)

'''

a 1

args {'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})

'''

a: 1

b: 2

c: 0

arg: ()

kwargs: {'k': 3}

a: 1

b: 2

c: 3

arg: (4, 5)

kwargs: {}

a: 1

b: 2

c: 3

arg: ()

kwargs: {'d': 4}

a: 1

b: 2

c: 3

arg: ()

kwargs: {'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")

'''

a: 1

b: 2

c: 0

args: ()

kwargs: {}

a: 3

b: 4

c: 5

args: (6, 7)

kwargs: {'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():

pass

a = demo1()

print(a) #None

return 可以返回一个值,也可返回多个值,当返回多个值 那么返回的是一个元组

def demo1():

return 1,2,3,4

a = 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 float

The numerator.

y : int or float

The denominator.

Returns

-------

float

The result of x divided by y.

"""

return x / y

七.函数的类型

空函数

函数体不完成任何功能,只有一个pass

def demo1():

pass

a = 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 * x

result = high_order_function(square) # 输出: 100

print(result)

九.偏函数

偏函数(Partial Function)是指通过固定一个函数的部分参数来创建一个新的函数。在Python中,可以使用 functools 模块中的 partial() 函数来实现偏函数。这种方式特别有用,可以使函数更加灵活和简洁。

from functools import partial

def 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_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 wrapper

return 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,常用于路由、请求处理和权限控制。。

其实要掌握也很简单,照抄写法就行 主要是带参数的装饰器。。

十一.总结

其实函数还有一大模块,变量和作用域,这一概念需要单独提出来写,函数这一概念 重点注意 参数传递/调用/返回值/装饰器,特别是装饰器 这东西实在太强大了,相比其他语言想要实现这一功能就要复杂很多!

创作整理不易,请大家多多关注 多多点赞,有写的不对的地方欢迎大家补充,我来整理,再次感谢!