函数进阶语法

1. 函数参数的高级用法

1.1 位置参数与关键字参数

位置参数是最常见的参数传递方式,根据函数定义时参数的顺序,依次将实参赋值给形参。

  • 必须按顺序传递,数量和类型必须与函数定义匹配。
  • 调用时不指定参数名,仅通过位置对应。

关键字参数通过参数名(关键字)指定对应关系,无需按顺序传递。

  • 调用时使用 参数名=值 的形式。
  • 可以跳过某些参数(如果有默认值)或按任意顺序传递。
# 位置参数
def greet(name, message):
    return f'{name},{message}!'
# 位置参数 按照参数的顺序进行赋值
print(greet("张三", "早上好"))
print(greet('早上好', '张三'))

# 关键字参数 指定某一个参数为某一个值 顺序可以打乱
print(greet(name = "张三", message="早上好"))
print(greet(message="早上好", name="张三"))

位置参数必须在关键字参数之前

# 如果要和位置参数混用的,位置参数必须在关键字参数之前
# SyntaxError: positional argument follows keyword argument
# print(greet(name="张三", "早上好"))
print(greet("张三", message="早上好"))

仅限位置参数:使用 / 标记之前的参数不能通过关键字传递

# 使用 `/` 标记之前的参数**不能**通过关键字传递
def func(a, b, /, c):
    pass


func(1, 2, 3)
func(1, 2, c=3)
# TypeError: func() got some positional-only arguments passed as keyword arguments: 'a, b'
func(a=1, b=2, c=3)

仅限关键字参数:使用 * 标记之后的参数必须通过关键字传递

# 使用 `*` 标记之后的参数必须通过关键字传递
def func(a, b, *, c, d):
    pass

# TypeError: func() takes 2 positional arguments but 4 were given
# func(1, 2, 3, 4)
# SyntaxError: positional argument follows keyword argument
# func(a = 1, b = 2, 3, 4)
# func(1, 2, c=3, 4)
func(1, 2, c=3, d=4)

1.2 默认参数值

是函数定义时为参数指定的预定义值。当调用函数时,如果没有为这些参数提供实际值,则会使用默认值。

# 默认参数
def greet(name, message="你好"):
    return f'{name},{message}!'
print(greet("王五"))
print(greet("王五", "早上好"))
print(greet("王五", message="晚上好"))

arr = ["123","23","3"]
arr.sort(reverse=True, key=len)
print(arr)
# 第一层含义 给调用者提示
# 第二层含义 增加函数的功能

必须在位置参数之后:默认参数不能出现在位置参数之前,否则会导致语法错误。

# 错误示例
def func(a = 1 ,b):
    pass

默认值在函数定义时计算一次:默认值在函数定义时被创建,而不是每次调用时重新创建。这可能导致可变对象(如列表、字典)的意外行为。

def add_item(item, items=[]):
    items.append(item)
    return items
# 多个add_item的调用使用的都是同一个items
# 在第一次调用时 给items进行初始值
print(add_item(1)) # 1
print(add_item(2)) # 1 2

arr1 = []
print(add_item(3,arr1)) # 3
arr2 = []
print(add_item(4, arr2))# 4

print(add_item(5))
print(add_item(6))
  • 修正方法:使用 None 作为默认值,并在函数内部初始化可变对象。
def add_item(item, items=None):
    if items is None:
        items = []
    items.append(item)
    return items
print(add_item(1)) # 1
print(add_item(2)) # 2

arr1 = []
print(add_item(3,arr1)) # 3
arr2 = []
print(add_item(4, arr2))# 4

print(add_item(5)) # 5
print(add_item(6)) # 6

多个默认参数:函数可以有多个默认参数,调用时可选择性地覆盖部分或全部默认值

def calculate(a, b=1, c=2):
    return a + b * c
print(calculate(10))
print(calculate(10,3))
print(calculate(10,3,4))
print(calculate(10, c = 4, b = 5))

默认参数与关键字参数结合:默认参数通常与关键字参数一起使用,允许跳过某些参数或按任意顺序传递参数

def config(host="localhost", port=8080, debug=False):
    print(f"{host},{port},{debug}")

config(debug=True)
config(port=3000)
config("127.0.0.1",80,False)

仅限关键字参数与默认值:使用 * 分隔符可以定义仅限关键字的默认参数

def func(a , *, b=10):
    return a + b
# 错误
# print(func(5,20))
print(func(5,b=20))

1.3 可变参数 *args

允许函数接收任意数量的参数,无需在定义时明确指定参数的个数。

# 可变参数 传入一个列表/元组 接受任意个参数
def sum_all(base, r=1, *numbers):
    total = base
    for num in numbers:
        total = total + num ** r
    return total
print(sum_all(10, 2, 1,2,3,4,5,6,7,8))

# 可变参数 传入一个列表/元组 接受任意个参数
def sum_all(base, *numbers, r=1):
    total = base
    for num in numbers:
        total = total + num ** r
    return total
print(sum_all(10, 1,2, 3, 4, 5, 6, 7, 8, r=2))


# 可变参数 传入一个列表/元组 接受任意个参数
def sum_all(*numbers, base, r=1):
    total = base
    for num in numbers:
        total = total + num ** r
    return total
print(sum_all(1, 2, 3, 4, 5, 6, 7, 8,base = 10,r=2))

# 可变参数 传入一个列表/元组 接受任意个参数
def sum_all(*numbers, r=1, base):
    total = base
    for num in numbers:
        total = total + num ** r
    return total
print(sum_all(1, 2, 3, 4, 5, 6, 7, 8, r=2, base=10))

def sum_all(*numbers, r=1, base):
    total = base
    for num in numbers:
        total = total + num ** r
    return total

arr = [1,2,3,4,5]
# 使用列表或元素进行解包
print(sum_all(*arr, r = 2, base=10))

1.4 关键字可变参数 **kwargs

允许函数接收任意数量的关键字参数(即带名称的参数),这些参数在函数内部会被收集为一个字典(dict)。

def create_profile(**user_info):
    profile = []
    for key , value in user_info.items():
        profile.append(f'{key}:{value}')
    return profile

print(create_profile(name="张三", age=30, city="北京"))

user = {'name':'李四', 'age':30, 'job':'工程师'}
# 将字典数据解包为关键字可变参数
print(create_profile(**user))

与普通参数混合使用:关键字可变参数必须放在函数参数列表的最后,且可与普通参数、位置可变参数组合使用

def func(a, b=10, *args, c=10, **kwargs):
    print(f'位置参数a = {a}')
    print(f'默认参数b = {b}')
    print(f'默认参数c = {c}')
    print(f'可变参数args = {args}')
    print(f'关键字可变参数kwargs = {kwargs}')
    print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~")


func(1)
func(1, 2)
func(1, 2, 3, 4, 5, 6, c=7)
func(1, 2, 3, 4, 5, 6, c=7, x=8, y=9)
func(1,3,3,4,5,6,x=7,y=8,z=9)

1.5 混合使用各种参数

  1. 参数顺序:位置参数 → 默认参数 → 可变参数(*args)→ 关键字参数 → 关键字可变参数(**kwargs)。
  2. 调用方式
    • 位置参数按顺序传递,无需指定名称。
    • 默认参数可省略,或通过关键字覆盖。
    • 可变参数接收额外的位置参数,打包为元组。
    • 关键字参数通过 name=value 传递。
    • 关键字可变参数接收额外的关键字参数,打包为字典。

2. 函数的高级特性

2.1 函数注解

是一种为函数参数和返回值添加元数据的语法。它允许你为参数和返回值关联任意类型的表达式(通常是类型),但不会影响函数的实际行为。函数注解主要用于文档、类型检查或第三方工具(如静态类型检查器、IDE 提示)。

  • 函数注解使用冒号(:)为参数添加类型提示,使用 -> 为返回值添加类型提示:
def add(a:int,b:int) -> int:
    return a + b
print(add("123","456"))
  • 注解的特点:
    • 不强制类型检查:Python 解释器不会强制执行注解的类型,它们只是元数据。
    • 可存储任意表达式:注解可以是任何类型的对象(如字符串、类、函数等),但通常用于类型提示。
    • 通过 __annotations__ 属性访问:函数的注解存储在其 __annotations__ 属性中。
def add(a:"这是参数a建议整数",b:"这是参数b建议整数") -> "返回值建议整数":
    return a + b
print(add("123","456"))
print(add.__annotations__)

2.2 闭包函数

是指有权访问另一个函数作用域中的变量的函数。即使该外部函数已经执行完毕,其作用域内的变量也不会被销毁,而是会被闭包捕获并保留在内存中。闭包使得函数可以 “记住” 它创建时的环境,即使环境已经不存在。

闭包形成的三个条件:

  • 函数嵌套:内部函数定义在外部函数内部。
  • 内部函数引用外部函数的变量:内部函数使用了外部函数作用域中的变量。
  • 外部函数返回内部函数:外部函数将内部函数作为返回值。
def outer_function(x):
    def inner_function(y):
        return x + y        # 内部函数引用外部函数的变量x
    return inner_function

func = outer_function(10)
print(func(5))

闭包的特点:

  • 捕获变量值:闭包捕获的是变量的值,而不是变量本身。
  • 保持状态:闭包可以记住其创建时的环境,即使外部函数已经执行完毕。
  • 独立实例:每次调用外部函数都会创建一个新的闭包实例,它们之间互不影响。
def outer_function(x):
    def inner_function(y):
        return x + y        # 内部函数引用外部函数的变量x
    return inner_function

func = outer_function(10)
print(func(5))
print(func(10))
func = outer_function(20)
print(func(10))
print(func(20))

# 做一个计数器
def counter():
    count = 0;
    def increment():
        # 如果需要再闭包中修改外部函数的变量,必须使用nonlocal声明
        nonlocal count
        count += 1
        return count
    return increment
c1 = counter() # 创建一个计数器
print(c1()) # 计数+1
print(c1()) # 计数+1
print(c1()) # 计数+1
c2 = counter()# 创建另一个计数器
print(c2())

闭包与普通函数区别

特性 闭包 普通函数
捕获外部变量 可以访问并保留外部函数的变量 只能访问全局变量或参数(局部变量)
状态保持 每个闭包实例独立维护状态 不保存状态,每次调用独立执行
创建方式 通过函数嵌套并返回内部函数 直接定义

2.3 装饰器

是一种特殊的函数或类,用于在不修改原函数代码的情况下,扩展或修改函数的行为。装饰器本质上是一个高阶函数,它接受一个函数作为参数,并返回一个新的函数

装饰器的核心作用是增强函数功能,例如添加日志、计时、权限验证等功能,而不需要修改原函数的代码。

使用 @装饰器名 语法糖将装饰器应用到函数上

基本装饰器

计时装饰器

import time
# def selection_sort(arr):
#     for i in range(0, len(arr) - 1):
#         for j in range(i + 1, len(arr)):
#             if arr[i] > arr[j]:
#                 arr[i], arr[j] = arr[j], arr[i]
#     return arr
#
# def bubble_sort(arr):
#     for i in range(0, len(arr) - 1):
#         for j in range(0, len(arr) - 1 - i):
#             if arr[j] > arr[j + 1]:
#                 arr[j], arr[j + 1] = arr[j + 1], arr[j]
#     return arr
#
# def sort_timer(sort_func, arr):
#     start = time.time()
#     sort_func(arr)
#     end = time.time()
#     print(end - start)
#
# arr = [1,5,2,6,2,7,9,3,5,7,3,2]
# # 排序 和 计时 的一个组合而已
# sort_timer(selection_sort, arr)
# sort_timer(bubble_sort, arr)
# selection_sort(arr)

# 计时装饰器函数
def timer(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"{func.__name__} 执行时间:{end - start:0.6f}秒数")
        return result
    return wrapper

@timer
def selection_sort(arr):
    for i in range(0, len(arr) - 1):
        for j in range(i + 1, len(arr)):
            if arr[i] > arr[j]:
                arr[i], arr[j] = arr[j], arr[i]
    return arr


def bubble_sort(arr):
    for i in range(0, len(arr) - 1):
        for j in range(0, len(arr) - 1 - i):
            if arr[j] > arr[j + 1]:
                arr[j], arr[j + 1] = arr[j + 1], arr[j]
    return arr

arr = [1,5,2,6,2,7,9,3,5,7,3,2]
print(selection_sort(arr))
print(timer(bubble_sort)(arr))

日志装饰器:

def log_decorator(func):
    def wrapper(*args, **kwargs):
        print(f'调用函数{func.__name__},参数:{args}, {kwargs}')
        result = func(*args, **kwargs)
        print(f'计算结果:{result}')
    return wrapper

@log_decorator
def add(a, b):
    return a + b
@log_decorator
def subtract(a, b):
    return a - b
@log_decorator
def multiply(a, b):
    return a * b
@log_decorator
def divide(a, b):
    return a / b

add(1,3)
subtract(1,3)
multiply(1,3)
divide(1,3)
多个装饰器
def bold(func):
    def wrapper(text):
        print("bold")
        print(func.__name__)
        return f'<b>{func(text)}</b>'
    return wrapper

def italic(func):
    def wrapper(text):
        print("italic")
        print(func.__name__)
        return f'<i>{func(text)}</i>'
    return wrapper

# 多个装饰器应用顺序从下到上的
@italic # 装饰器的装饰器
@bold
def format_text(text):
    return text

print(format_text("Hello World"))
"""
<b><i>文本数据</i></b>

"""

2.4 函数作为对象

Python当中,万事万物皆对象,函数也可以当做参数或者返回值进行传递!

def add(a, b):
    return a + b


def subtract(a, b):
    return a - b


def multiply(a, b):
    return a * b


def divide(a, b):
    return a / b


operations = {
    "+": add,
    "-": subtract,
    "*": multiply,
    "/": divide
}


# 第一种调用方式
def calculate(operation, a, b):
    return operation(a, b)


print(calculate(add, 10, 5))
# 第二种调用方式
op = "*"
print(operations[op](10, 5))
# 第三种调用方式
def choice_operation(op):
    operation = operations[op]
    return operation # add
print(choice_operation("+")(10,5))
print(choice_operation("-")(10,5))

2.5 函数组合

"""
f(x) g(x) h(x)
f(g(h(x)))
"""
def compose(*functions):
    def inner(x):
        result = x
        for f in reversed(functions):
            result = f(result)
        return result
    return inner

def add(x):
    return x + 1
def double(x):
    return x * 2
def square(x):
    return x ** 2

f = compose(square, double, add)
print(f(5)) # ((5+1)*2)^2

3. 生成器函数

是一种特殊的函数,它使用 yield 关键字代替 return 来返回值,并且可以在每次调用时暂停和恢复执行状态。生成器函数创建的对象称为生成器(Generator),它是一种迭代器,支持惰性计算,能显著节省内存。

  • yield 关键字:生成器函数使用 yield 暂停执行并返回一个值,下次调用时从暂停处继续执行。
  • 惰性计算:生成器只在需要时生成值,适合处理大量数据或无限序列。
  • 状态保存:生成器会自动保存函数的局部状态,无需额外管理(利用了闭包的特性)。

3.1 基本生成器

生成数字

# 生成从1到n的数字
def count_up_to(n):
    i = 1
    while i <= n:
        yield i
        i += 1
# 生成器函数(迭代器)
counter = count_up_to(3)
print(next(counter))
print(next(counter))
print(next(counter))
# StopIteration
# print(next(counter))

for num in count_up_to(3):
    print(num)

无限斐波那契数列

"""
1 1 2 3
    a b
1 1 2
"""
def fibonacci():
    a, b = 1, 1
    while True:
        yield a
        a, b = b, a + b
fib = fibonacci()
n = 0
while n < 1000:
    print(next(fib))
    n += 1

3.2 生成器表达式

生成器只能遍历一次,遍历结束后需要重新创建。

# 列表推导式 推出所有的元素
arr = [x ** 2 for x in range(1,6)]
print(arr)
# 数据已有 挨个遍历
for num in arr:
    print(num)
# 生成器表达式 不会推出所有的元素
arr = (x ** 2 for x in range(1,6))
print(arr)
# 数据没有 挨个生成
for num in arr:
    print(num)
# 此时元素已经生成完毕 生成结束
for num in arr:
    print(num)

3.3 yield from 语句

yield from 是一个用于简化生成器嵌套的语法,它允许一个生成器委托部分操作给另一个生成器。

就是将多个数据源创(序列,集合,生成器函数,迭代器)建为一个生成器

def data1():
    yield from [1, 2, 3]
def count_up_to(n):
    i = 1
    while i <= n:
        yield i
        i += 1
def data2():
    yield from count_up_to(5)
    yield from data1()
    yield from ('a', 'b', 'c')
    yield from range(4, 6)

for item in data2():
    print(item)

生成器 vs. 普通函数

特性 生成器函数 普通函数
返回关键字 使用 yield 多次返回值 使用 return 一次性返回值
执行状态 暂停和恢复,保留局部状态 执行完毕后销毁所有状态
内存效率 按需生成,节省内存 一次性生成所有结果,可能占用大量内存
返回类型 生成器对象(迭代器) 返回具体值
可迭代次数 一次性迭代,耗尽后需重建 可重复调用

4. 函数式编程

4.1 lambda 表达式

是一种用于创建匿名函数的简洁语法。它允许在需要函数的地方直接定义轻量级函数,无需使用 def 关键字显式命名。lambda 表达式通常用于简单的函数逻辑,例如在高阶函数(如 mapfiltersorted)中作为参数传递。

基本语法

lambda 参数列表: 表达式
  • 参数列表:可以是单个参数、多个参数,甚至可变参数(如 *args**kwargs)。
  • 表达式:函数的返回值,只能是一个表达式(不能包含语句,如 iffor 等)。
greet = lambda: "Hello!"
print(greet())
"""
def greet():
 return "Hello"
"""

square = lambda x: x ** 2
print(square(5))
"""
def square(x):
 return x ** 2
"""

add = lambda x, y:x + y
print(add(1,2))
"""
def add(x, y):
    return x + y
"""

与普通函数的区别

特性 lambda 表达式 普通函数(def)
定义方式 无名称,使用 lambda 关键字 有名称,使用 def 关键字
表达式数量 只能有一个表达式(返回值) 可以包含多个语句(如 if、循环)
文档字符串 不支持 支持(__doc__ 属性)
调试难度 较难(无名称,堆栈信息不明确) 较容易(有名称,堆栈信息清晰)
适用场景 简单逻辑、临时使用 复杂逻辑、需要重复调用
students = [
    {"name": "张三", "score": 85},
    {"name": "李四", "score": 92},
    {"name": "王五", "score": 78},
]
s = sorted(students, key=lambda item:item['score'], reverse=True)
print(s)

def my_key(item):
    return item['score']
s = sorted(students, key=my_key, reverse=True)
print(s)

4.2 map 函数

# 使用map函数将传入的函数应用到可迭代对象的每个元素
numbers = [1, 2, 3, 4, 5]
# l = [x ** 2 for x in numbers]
# l = (x ** 2 for x in numbers)

l = list(map(lambda x: x ** 2, numbers))
print(l)


def cube(x):
    return x ** 3


l = list(map(cube, numbers))
print(l)

l1 = [1, 2, 3]
l2 = [10, 20, 30]
l3 = list(map(lambda x, y: x + y, l1, l2))
print(l3)

4.3 filter 函数

# 使用filter 函数筛选可迭代对象中的元素
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
l = list(filter(lambda x: x % 2 == 0, numbers))
print(l)

def is_prime(n):
    if n < 2:
        return False
    for i in range(2, int(n ** 0.5) + 1):
        if n % i == 0:
            return False
    return True
l = list(filter(is_prime, numbers))
print(l)

l = list(filter(lambda x:is_prime(x), numbers))
print(l)

4.4 reduce 函数

# 使用reduce函数对迭代对象中的元素进行累积操作
from functools import reduce

numbers = [1, 2, 3, 4, 5]
# sum(numbers)
l = reduce(lambda x, y: x + y, numbers)
print(l)
# 阶乘/累成
l = reduce(lambda x, y: x * y, numbers)
print(l) # 1 * 2 * 3 * 4 * 5
# 错误示例 返回1 耗时操作
l = reduce(lambda x, y: x ** y, numbers)
print(l)
print(1 ** 2 ** 3 ** 4 ** 5)
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐