Python 函数用法

Python 函数是编程的核心,它通过 def关键字将代码封装为可重用的模块,大幅提升代码的清晰度和维护性。

函数的定义与调用

在 Python 中,我们使用 def关键字来定义函数。一个典型的函数结构如下:

def greet(name):    # `greet` 是函数名,`name` 是参数
		"""
    向指定的人打招呼。  # 这是文档字符串 (Docstring),用于说明函数用途
    """
    message = f"Hello, {name}!"# 函数体:具体的执行逻辑
    return message    # 使用 return 语句返回结果
    
# 调用函数,'Alice' 是实际传递给参数 `name` 的值(实参)
result = greet('Alice')
print(result)    # 输出:Hello, Alice!
  • 定义与调用:函数需要先定义,后调用。定义函数相当于制造工具,而调用函数才是使用工具。
  • 返回值:return是函数结束的标志,它会将结果返回给调用者。如果函数没有 return语句,它会自动返回 None。

参数传递

  1. 位置传参

这是最直观的方式。调用函数时,传入的实参会按照位置顺序依次赋值给形参。

def introduce(name, age, city): 
		print(f"大家好,我叫{name},今年{age}岁,来自{city}。") 

introduce("张三", 25, "北京")# 输出:大家好,我叫张三,今年25岁,来自北京。

在这里,”张三”传给 name,25传给 age,”北京”传给 city。顺序至关重大。

  1. 关键字传参

顺序虽然打乱,但通过关键字准确匹配。关键字参数必须放在所有位置参数之后,例如 introduce(“王五”, city=”广州”, age=28)是合法的,但 introduce(name=”王五”, 28, “广州”)会导致语法错误。

通过 explicitly 指定参数名来传递值,这种方式不依赖于参数的位置,使得代码更清晰,尤其在参数众多时。

def introduce(name, age, city): 
		print(f"大家好,我叫{name},今年{age}岁,来自{city}。")

introduce(age=30, city="上海", name="李四") # 输出:大家好,我叫李四,今年30岁,来自上海。
  1. 默认参数定义时,带有默认值的参数必须放在所有非默认参数(位置参数)的后面

在定义函数时,可以为某些参数指定默认值。这样在调用函数时,如果省略这些参数,就会使用其默认值。这极大地增加了函数的灵活性。

def greet(name, greeting="Hello"): 
		print(f"{greeting}, {name}!") 

greet("Alice") # 输出:Hello, Alice! (使用默认的greeting) 
greet("Bob", "Hi") # 输出:Hi, Bob! (覆盖默认的greeting)
  1. 可变位置参数 (args)

在形参前加一个 *,如 *args(名称习惯用 args,但关键是 *)。它会将调用时传入的所有多余的位置参数收集到一个元组中。

def sum_numbers(*args): 
		total = 0
		for num in args:
    		total += num 
		return total 

print(sum_numbers(1, 2, 3)) # 输出:6 
print(sum_numbers(10, 20, 30, 40)) # 输出:100
  1. 可变关键字参数 (*kwargs)

在形参前加两个 *,如 **kwargs(名称习惯用 kwargs)。它会将调用时传入的所有多余的关键字参数(即未在形参列表中定义的键值对)收集到一个字典中。

def print_profile(**kwargs): 
		for key, value in kwargs.items(): 
    		print(f"{key}: {value}") 

print_profile(name="Charlie", age=35, occupation="Engineer") 
# 输出: 
# name: Charlie 
# age: 35 
# occupation: Engineer
  1. 参数混合使用与顺序规则强制顺序规则为:位置参数 -> 默认参数 -> *args -> 关键字参数(或称keyword-only参数,如d和e) -> **kwargs。

以上几种方式可以混合在一个函数定义中,但必须遵循严格的顺序,否则Python解释器无法正确解析:

def complex_example(a, b, c=10, *args, d, e=20, **kwargs): 
		print(f"a={a}, b={b}, c={c}") 
		print(f"args tuple: {args}") 
		print(f"d={d}, e={e}") 
		print(f"kwargs dict: {kwargs}") 

# 调用示例 complex_example(1, 2, 3, 4, 5, d=6, f=7, g=8) 
# 输出: 
# a=1, b=2, c=3 
# args tuple: (4, 5) # 位置参数a,b,c分配后,剩下的4和5给了args 
# d=6, e=20 # d必须用关键字指定,e使用了默认值 
# kwargs dict: {'f': 7, 'g': 8}  # 多余的关键字参数

传参的“值”与“引用”

这是一个重大致念,它决定了函数内部对参数的操作是否会影响到函数外部的原始变量。

  • 传递不可变对象(值传递/传值):当传入的实参是不可变对象,如整数、字符串、元组时,函数内部对形参的任何修改(如重新赋值)都只发生在函数内部,不会影响外部的实参。这相当于传递了一个副本。
def try_change_immutable(x): 
		x = x + 10 # 尝试修改 
    print("函数内 x =", x) 
num = 5 
try_change_immutable(num) # 输出:函数内 x = 15 
print("函数外 num =", num) # 输出:函数外 num = 5 (未改变)
  • 传递可变对象(引用传递/传引用):当传入的实参是可变对象,如列表、字典时,传递的是指向该对象的“引用”。函数内部对形参内容的修改(如修改列表元素、向字典添加键值对)会直接影响外部的实参如果不想改变原列表,可以在传参时传递一个副本,例如使用切片 function_name(my_list[:])或 list(my_list)。
def try_change_mutable(my_list): 
		my_list.append(4) # 修改列表内容 
    print("函数内 my_list =", my_list) 

lst = [1, 2, 3] 
try_change_mutable(lst) # 输出:函数内 my_list = [1, 2, 3, 4] 
print("函数外 lst =", lst) # 输出:函数外 lst = [1, 2, 3, 4] (已被改变)

变量作用域

在函数内部定义的变量属于局部作用域,只在函数内部有效。而在函数外部定义的变量则属于全局作用域

  • 局部变量:在函数内创建,函数执行完毕后会被销毁,外部无法访问。
  • 全局变量:在函数外创建,可以在整个程序(包括函数内部)被访问。
  • 修改全局变量:如果需要在函数内部修改全局变量,需要使用 global关键字进行声明。
count = 0    # 全局变量
def increment():
    global count    # 声明要修改全局变量 count
    count += 1
    local_var = "inside"    # 局部变量,函数外部无法访问

increment()
print(count)    # 输出: 1
# print(local_var)    # 这行会报错,由于 local_var 未定义

高阶用法

除了基础用法,函数还有一些强劲的高级特性:

  1. Lambda 匿名函数:用于定义简单的、单行就能实现的函数,使用 lambda关键字。
square = lambda x: x ** 2 # 一个计算平方的匿名函数 
print(square(5)) # 输出: 25
  1. 函数作为参数与返回值(高阶函数):函数本身也可以作为值传递给另一个函数,或者作为另一个函数的返回值。这是函数式编程的基础。
def apply_operation(x, y, operation): 
		return operation(x, y) 

result = apply_operation(10, 5, lambda a, b: a + b) # 传递一个加法函数 
print(result) # 输出: 15
  1. 闭包

闭包的本质是函数和与其相关的引用环境的组合。当内部函数引用了外部函数的变量时,Python 会将这些变量(自由变量)绑定到内部函数上,形成一个闭包。即使外部函数执行完毕,其局部作用域本应销毁,但由于闭包的存在,这些被引用的变量会继续存活,供内部函数后续使用 。

一个简单的例子能清晰地展示这一点:

def outer_function(x):  # 外部函数 
		def inner_function(y):  # 内部函数 
    		return x + y # 内部函数引用了外部函数的变量x(自由变量) 
    return inner_function # 外部函数返回内部函数 
    
    # 创建闭包实例,此时outer_function已执行完毕,但x=10被记住了 
    closure = outer_function(10) 

print(closure(5)) # 输出 15 (10 + 5) 
print(closure(20)) # 输出 30 (10 + 20)

在这个例子中,inner_function就是一个闭包。它捕获并记住了外部函数outer_function的参数x=10。之后每次调用closure,它都能使用这个记住的x的值 。

  1. 装饰器:一种强劲的工具,允许你在不修改原函数代码的情况下,为其增加新的功能。它本质上利用了函数可以作为参数和返回值的特性。装饰器是 Python 中超级强劲的语法糖,其底层实现是闭包。
def my_decorator(func): 
		def wrapper(): 
    		print("函数执行前...") 
				func() 
				print("函数执行后...") 
		return wrapper 

@my_decorator 
def say_hello(): 
		print("Hello!") 

say_hello() 
# 输出: 
# 函数执行前... 
# Hello! 
# 函数执行后...
© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
胡元元的头像 - 鹿快
评论 抢沙发

请登录后发表评论

    暂无评论内容