找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

753

积分

0

好友

97

主题
发表于 3 小时前 | 查看: 1| 回复: 0

太棒了!欢迎来到 Python 30 天学习计划的第 10 天!🎉
今天我们将深入 函数进阶(Advanced Functions) —— 掌握让函数更灵活、更专业、更易维护的核心技巧。函数是 Python 的“积木块”,学会这些高级用法,你就能写出像标准库一样优雅、通用的代码!

🎯 第10天目标:

  • ✅ 理解并正确使用默认参数(避免常见陷阱)
  • ✅ 掌握关键字参数提升代码可读性
  • ✅ 灵活运用 *args**kwargs 实现可变参数函数
  • ✅ 编写规范的 文档字符串(docstring),让代码自解释

📘 一、默认参数(Default Arguments)

默认参数为参数提供了“备用值”,在调用函数时可以省略。

🔹 基本用法

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

print(greet("Alice")) # Hello, Alice!
print(greet("Bob", "Hi")) # Hi, Bob!

⚠️ 经典陷阱:可变默认参数

# ❌ 危险!不要这样做!
def add_item(item, target_list=[]):
    target_list.append(item)
    return target_list

list1 = add_item("apple")
list2 = add_item("banana")
print(list1) # ['apple', 'banana'] ← 意外共享!
print(list2) # ['apple', 'banana']

原因:默认参数在函数定义时创建一次,后续所有调用都会共享同一个可变对象(列表)!

# ✅ 正确做法:用 None 作哨兵
def add_item(item, target_list=None):
    if target_list is None:
        target_list = []
    target_list.append(item)
    return target_list

list1 = add_item("apple")
list2 = add_item("banana")
print(list1) # ['apple']
print(list2) # ['banana']

🔑 黄金法则永远不要用可变对象(list, dict, set)作为默认参数! 应使用 None 作为默认值,然后在函数体内部进行初始化。

📘 二、关键字参数(Keyword Arguments)

在调用函数时通过 参数名=值 的形式传递参数,这种方式可读性更高,并且传递顺序可以自由调整。

🔹 示例

def create_user(name, age, city="Unknown", active=True):
    return {"name": name,
            "age": age,
            "city": city,
            "active": active}

# 位置参数
user1 = create_user("Alice", 30)
# 混合使用(位置 + 关键字)
user2 = create_user("Bob", 25, city="New York")
# 全关键字(推荐用于多参数函数)
user3 = create_user(name="Charlie",
                    age=35,
                    active=False,
                    city="London")

print(user2)
# {'name': 'Bob', 'age': 25, 'city': 'New York', 'active': True}

🔹 强制关键字参数(Keyword-Only Arguments)

使用 * 作为分隔符,其后的参数在调用时必须以关键字形式传入。

def connect(host, port, *, timeout=5, secure=True):
    print(f"Connecting to {host}:{port}, timeout={timeout}s, secure={secure}")

# connect("example.com", 443, 10)  ❌ 报错!timeout 必须用关键字
# ✅ 正确用法
connect("example.com", 443, timeout=10)

用途:当函数参数较多、易混淆时,强制使用关键字参数能有效提高代码清晰度,避免传参错误。

📘 三、*args:接收任意数量的位置参数

*args 会将函数调用时传递的多余位置参数收集为一个元组

🔹 示例:通用求和函数

def sum_all(*args):
    print(f"Received args: {args}") # args 是元组
    return sum(args)

print(sum_all(1, 2, 3))
# Received args: (1, 2, 3) → 6
print(sum_all(10, 20, 30, 40))
# Received args: (10, 20, 30, 40) → 100

🔹 拆包(Unpacking)反向使用

numbers = [1, 2, 3, 4]
print(sum_all(*numbers))
# 等价于 sum_all(1, 2, 3, 4)

💡 简单记忆:* 在函数定义时表示“收集”参数,在函数调用时表示“拆包”序列。

📘 四、**kwargs:接收任意数量的关键字参数

**kwargs 会将函数调用时传递的多余关键字参数收集为一个字典

🔹 示例:创建灵活配置

def configure_app(name, **kwargs):
    config = {"app_name": name}
    config.update(kwargs) # 合并额外配置
    return config

app = configure_app("MyApp", debug=True, port=8080, host="localhost")
print(app)
# 输出:{'app_name': 'MyApp', 'debug': True, 'port': 8080, 'host': 'localhost'}

🔹 拆包字典

settings = {"debug": True, "port": 3000}
app2 = configure_app("WebApp", **settings)
print(app2)
# 等价于 configure_app("WebApp”, debug=True, port=3000)

📘 五、组合使用:完整的函数签名

虽然 Python 支持复杂的参数顺序,但最常用且实用的模式是:

def flexible_func(required, default_val="default", *args, **kwargs):
    print(f"Required: {required}")
    print(f"Default: {default_val}")
    print(f"Extra args: {args}")
    print(f"Extra kwargs: {kwargs}")

flexible_func("hello", "world", 1, 2, 3, color="red", size="large")

输出

Required: hello
Default: world
Extra args: (1, 2, 3)
Extra kwargs: {'color': 'red', 'size': 'large'}

✅ 这种参数模式在装饰器、Web 框架(如 Flask 路由)等需要高度灵活性的场景中被广泛使用!

📘 六、文档字符串(Docstring)—— 让函数会说话

三重引号 编写的注释,用于描述函数用途、参数、返回值,是实现代码自解释的关键。

🔹 Google 风格(推荐)

def calculate_tax(income, rate=0.1):
    """计算个人所得税。

    Args:
        income (float): 年收入,单位:元。
        rate (float, optional): 税率。默认为 0.1 (10%)。

    Returns:
        float: 应缴税额。

    Raises:
        ValueError: 如果 income 为负数。

    Examples:
        >>> calculate_tax(100000)
        10000.0
        >>> calculate_tax(50000, rate=0.05)
        2500.0
    """
    if income < 0:
        raise ValueError("收入不能为负数")
    return income * rate

🔹 查看 docstring

help(calculate_tax)  # 在 REPL 中查看
print(calculate_tax.__doc__)  # 直接打印

好处

  • 自动生成 API 文档(Sphinx, pdoc)
  • IDE 智能提示
  • 极大提升团队协作与代码维护效率

💻 今日实战:构建一个灵活的日志记录函数

综合运用今日所学,我们来编写一个功能完善的日志记录函数。它应支持默认参数、可变参数(*details)和任意关键字参数(**metadata)。

Python函数日志记录示例代码截图

✅ 今日小任务

*1、修改计算器函数,使其支持任意数量的数字相加/相乘(用 `args`)。**

Python计算器函数示例代码截图

2、思考题:为什么 def foo(a, b=10, *args, c) 会报错?

💡 答案:在 *args 之后的参数(如 c必须是关键字参数,但这里 c 没有提供默认值,调用时必须显式指定 c=...,而函数定义时却允许它以位置参数形式出现,造成了歧义。如果想允许 c 以位置传参,应放在 *args 前;如果想强制 c 为关键字参数,应使用 * 分隔或提供默认值:

def foo(a, b=10, *, c):  # c 必须关键字传入
    pass

📝 小结

特性 作用 注意事项
默认参数 提供备用值,简化调用 避免可变对象(用 None 替代)
关键字参数 提升可读性,传参顺序自由 参数较多时优先使用
*`args`** 接收任意数量的位置参数 收集为元组
`kwargs`** 接收任意数量的关键字参数 收集为字典
文档字符串 实现代码自文档化 遵循 Google/NumPy 等规范风格

最佳实践

  • 默认参数使用不可变对象。
  • 多参数函数优先使用关键字参数调用。
  • 所有公开的函数和方法都应撰写清晰的 docstring,这是优秀的技术文档习惯。
  • *args/**kwargs 用于需要极致灵活性的场景(如装饰器、API 封装)。

🎉 恭喜你完成第 10 天的学习!
你已经掌握了 编写专业级 Python 函数的核心技能,代码正变得越来越优雅!✨ 不妨将你的理解和实践代码记录下来,在云栈社区分享你的学习笔记,与其他开发者一起交流成长。




上一篇:AI全流程主导恶意软件开发:首曝VoidLink框架结构与技术影响
下一篇:开源AI短剧工具Huobao Drama:从脚本到视频全自动生成
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-24 20:19 , Processed in 0.327885 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表