Python函数:让你的代码学会“社交”的终极指南

函数就像代码世界里的社交达人,它们知道何时该说话(接受参数),何时该倾听(返回结果),以及如何在不同场合(作用域)表现得体。

一、函数的“社交技巧”:参数传递的艺术

1.1 位置参数:先来后到的规矩

def introduce(name, age, city):
"""最基本的参数传递方式,像排队一样讲究顺序"""
return f"我叫{name},今年{age}岁,来自{city}"

# 正确示范:按顺序传递参数
print(introduce("小明", 25, "北京")) # "我叫小明,今年25岁,来自北京"

# 尴尬场面:顺序错了
print(introduce("北京", "小明", 25)) # "我叫北京,今年小明岁,来自25" 😅

小细节:位置参数是函数的最基本要求,调用时必须提供,且顺序不能乱。

1.2 关键字参数:直接点名不排队

# 使用关键字参数,顺序不重要了
print(introduce(age=25, city="上海", name="小红"))
# 照样输出:"我叫小红,今年25岁,来自上海"

# 混合使用:位置参数必须在关键字参数之前
print(introduce("小刚", city="广州", age=30)) # ✅ 正确
print(introduce(name="小李", "深圳", age=28)) # ❌ 语法错误!

小贴士:当函数参数很多时,使用关键字参数可读性更强,减少出错概率。

1.3 默认参数:贴心的备胎值

def order_coffee(coffee_type, size="大杯", sugar="正常"):
"""给参数设置默认值,让调用更灵活"""
return f"一杯{size}{coffee_type},糖度:{sugar}"

# 只提供必填参数
print(order_coffee("拿铁"))
# "一杯大杯的拿铁,糖度:正常"

# 覆盖默认值
print(order_coffee("美式", size="中杯", sugar="无糖"))
# "一杯中杯的美式,糖度:无糖"

重要警告:默认参数有个大坑!

def add_item(item, shopping_list=[]):  # ❌ 危险!默认值是可变对象
shopping_list.append(item)
return shopping_list

print(add_item("苹果")) # ['苹果']
print(add_item("香蕉")) # ['苹果', '香蕉'] 等等,怎么有两个?!

# 正确做法:用None作为默认值
def add_item_safe(item, shopping_list=None):
if shopping_list is None:
shopping_list = []
shopping_list.append(item)
return shopping_list

1.4 收集参数:来者不拒的社交达人

*args:收集所有位置参数

def party_host(*args):
"""*args把位置参数打包成元组"""
print(f"今晚的客人有:{len(args)}位")
for guest in args:
print(f"- {guest}")

party_host("小明", "小红", "小刚", "小李")
# 今晚的客人有:4位
# - 小明
# - 小红
# - 小刚
# - 小李

**kwargs:收集所有关键字参数

def create_profile(**kwargs):
"""**kwargs把关键字参数打包成字典"""
profile = {}
for key, value in kwargs.items():
profile[key] = value
return profile

user = create_profile(name="小王", age=25, job="程序员", hobby="打游戏")
print(user) # {'name': '小王', 'age': 25, 'job': '程序员', 'hobby': '打游戏'}

全家福:所有参数一起上

def universal_function(required, *args, default="默认值", **kwargs):
"""参数界的满汉全席"""
print(f"必需参数: {required}")
print(f"额外位置参数: {args}")
print(f"默认参数: {default}")
print(f"额外关键字参数: {kwargs}")

universal_function("必须的", "额外1", "额外2",
default="覆盖默认", extra1="补充1", extra2="补充2")

1.5 参数解包:把礼物拆开送

def describe_person(name, age, city):
return f"{name} ({age}岁, {city})"

# 普通调用
print(describe_person("小明", 25, "北京"))

# 解包调用
data = ["小红", 30, "上海"]
print(describe_person(*data)) # 列表解包

info = {"name": "小刚", "age": 28, "city": "广州"}
print(describe_person(**info)) # 字典解包

二、作用域:变量的“社交圈子”

2.1 作用域层次:从村头到全球

global_var = "我是全局变量"  # 全球范围

def outer_function():
outer_var = "我是外层变量" # 城市范围

def inner_function():
inner_var = "我是内层变量" # 小区范围
print(f"内层能看到: {inner_var}")
print(f"内层能看到外层: {outer_var}")
print(f"内层能看到全局: {global_var}")

inner_function()
print(f"外层能看到: {outer_var}")
print(f"外层能看到全局: {global_var}")
# print(inner_var) # ❌ 错误!外层看不到内层的变量

outer_function()
print(f"全局能看到: {global_var}")
# print(outer_var) # ❌ 错误!全局看不到函数内的变量

2.2 global:我要改变世界!

counter = 0  # 全局变量

def increment():
global counter # 声明:我要修改全局变量!
counter += 1
print(f"当前计数: {counter}")

increment() # 当前计数: 1
increment() # 当前计数: 2
increment() # 当前计数: 3

小心陷阱:没有global会怎样?

x = 10

def confuse():
x = 20 # 这只是局部变量,不是修改全局的x
print(f"函数内的x: {x}")

confuse() # 函数内的x: 20
print(f"函数外的x: {x}") # 函数外的x: 10

2.3 nonlocal:我只想改变邻居家

def outer():
x = "原始值"

def inner():
nonlocal x # 声明:我要修改外层函数的变量!
x = "被修改了"
print(f"inner内部: {x}")

print(f"修改前: {x}")
inner()
print(f"修改后: {x}")

outer()
# 输出:
# 修改前: 原始值
# inner内部: 被修改了
# 修改后: 被修改了

重要区别

  • global:修改全局作用域的变量
  • nonlocal:修改外层(非全局)作用域的变量

三、函数嵌套:俄罗斯套娃式的代码

3.1 基本嵌套:函数里的函数

def bank_account(initial_balance):
"""闭包:一个会"记住"状态的函数"""
balance = initial_balance

def deposit(amount):
nonlocal balance
balance += amount
return f"存款{amount},当前余额:{balance}"

def withdraw(amount):
nonlocal balance
if amount > balance:
return "余额不足!"
balance -= amount
return f"取款{amount},当前余额:{balance}"

def check_balance():
return f"当前余额:{balance}"

# 返回内部函数的引用
return {"存钱": deposit, "取钱": withdraw, "查余额": check_balance}

# 创建小明的账户
ming_account = bank_account(1000)
print(ming_account["查余额"]()) # 当前余额:1000
print(ming_account["存钱"](500)) # 存款500,当前余额:1500
print(ming_account["取钱"](200)) # 取款200,当前余额:1300

# 创建小红的账户(完全独立!)
hong_account = bank_account(500)
print(hong_account["查余额"]()) # 当前余额:500

3.2 装饰器:给函数穿衣服

import time

def timer_decorator(func):
"""计算函数执行时间的装饰器"""
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"{func.__name__} 执行时间: {end_time - start_time:.4f}秒")
return result
return wrapper

# 使用装饰器
@timer_decorator
def slow_function():
"""一个假装很慢的函数"""
time.sleep(1)
return "任务完成!"

print(slow_function())
# slow_function 执行时间: 1.0001秒
# 任务完成!

3.3 lambda函数:匿名的社交恐惧者

# 传统函数定义
def add(x, y):
return x + y

# lambda版本(一行搞定!)
add_lambda = lambda x, y: x + y

print(add(3, 5)) # 8
print(add_lambda(3, 5)) # 8

# lambda的经典应用:排序
students = [
{"name": "小明", "score": 85},
{"name": "小红", "score": 92},
{"name": "小刚", "score": 78}
]

# 按分数排序
sorted_students = sorted(students, key=lambda x: x["score"], reverse=True)
for student in sorted_students:
print(f"{student['name']}: {student['score']}分")

四、实战演练:打造你的瑞士军刀函数

def swiss_knife(data, *processors, default="未处理", **options):
"""
一个多功能处理函数

参数:
- data: 要处理的数据
- *processors: 多个处理函数
- default: 默认返回值
- **options: 配置选项
"""

# 处理选项
verbose = options.get('verbose', False)
max_retries = options.get('max_retries', 3)

if verbose:
print(f"开始处理数据,重试次数:{max_retries}")

# 依次应用所有处理器
result = data
for i, processor in enumerate(processors, 1):
try:
result = processor(result)
if verbose:
print(f"第{i}个处理器完成,结果:{result}")
except Exception as e:
print(f"处理器{i}出错:{e}")
return default

return result

# 使用示例
def double(x):
return x * 2

def add_ten(x):
return x + 10

def square(x):
return x ** 2

result = swiss_knife(5, double, add_ten, square,
verbose=True, max_retries=5)
print(f"最终结果:{result}")

五、总结:函数社交指南

特性 一句话总结 使用场景
位置参数 排队进场,先来后到 简单函数,参数顺序明确
关键字参数 凭票入场,对号入座 参数多或可选参数多时
默认参数 自带干粮,有备无患 参数有常用默认值时
*args 来者不拒,统统收下 不确定需要多少位置参数时
**kwargs 名字很重要,按名收礼 不确定需要什么关键字参数时
global 我要改变世界! 需要修改全局变量时
nonlocal 我只改邻居家 闭包中修改外层变量时
函数嵌套 俄罗斯套娃,各玩各的 实现装饰器、闭包、工厂函数时

记住:好的函数就像好的社交达人,知道何时该严格(参数检查),何时该灵活(默认值),何时该开放(收集参数),何时该保护隐私(作用域隔离)。

现在,让你的Python函数出去社交吧!记得提醒它们:参数要清晰,作用域要明确,嵌套要有度。Happy coding! 🚀


彩蛋:测试你的理解

# 猜猜这个函数会输出什么?
def mystery(x, y=[]):
y.append(x)
return y

print(mystery(1))
print(mystery(2))
print(mystery(3, []))
print(mystery(4))

# 答案揭晓:
# [1]
# [1, 2] ← 咦?怎么还有1?
# [3]
# [1, 2, 4] ← 哇,越来越长了!
#
# 教训:永远不要用可变对象作为默认参数!