Python 函数完全指南:定义与调用

目录

[1. 什么是函数?](#1. 什么是函数?)

[2. 函数的定义](#2. 函数的定义)

[2.1 基本语法](#2.1 基本语法)

[2.2 带参数的函数](#2.2 带参数的函数)

[2.3 带返回值的函数](#2.3 带返回值的函数)

[2.4 空函数(占位)](#2.4 空函数(占位))

[3. 函数的调用](#3. 函数的调用)

[4. 参数类型详解](#4. 参数类型详解)

[4.1 位置参数(必须参数)](#4.1 位置参数(必须参数))

[4.3 关键字参数](#4.3 关键字参数)

[4.4 可变长度参数](#4.4 可变长度参数)

[4.5 参数组合顺序](#4.5 参数组合顺序)

[5. 返回值详解](#5. 返回值详解)

[5.1 单个返回值](#5.1 单个返回值)

[5.2 多个返回值(本质是返回元组)](#5.2 多个返回值(本质是返回元组))

[5.3 return 语句省略时返回 None](#5.3 return 语句省略时返回 None)

[5.4 return 提前退出函数](#5.4 return 提前退出函数)

[6. 作用域](#6. 作用域)

[6.1 局部变量与全局变量](#6.1 局部变量与全局变量)

[6.2 nonlocal 关键字(用于嵌套函数)](#6.2 nonlocal 关键字(用于嵌套函数))

[7. 函数也是对象](#7. 函数也是对象)

[8. 匿名函数(lambda)](#8. 匿名函数(lambda))

[9. 递归函数](#9. 递归函数)

[10. 类型注解(Type Hints)](#10. 类型注解(Type Hints))

[11. 常见内置函数示例](#11. 常见内置函数示例)

12.常见陷阱与最佳实践


在编程中,我们经常需要重复执行某段代码。如果每次都复制粘贴,不仅代码冗长,而且修改起来非常麻烦。函数就是解决这个问题的利器:它将一段具有独立功能的代码打包成一个"积木块",需要时只需"调用"即可。

1. 什么是函数?

函数是一段可重复使用的代码块,它接收输入(参数),进行处理,并可能返回输出(返回值)。函数可以帮你:

  • 避免重复:同样的逻辑只需写一次。

  • 模块化:将复杂程序拆分成小功能块。

  • 易维护:修改函数内部实现,所有调用处自动生效。

Python 内置了很多函数(如 print()、len()),你也可以自定义函数。

2. 函数的定义

2.1 基本语法

使用 def 关键字定义函数,后面跟函数名、括号 () 和冒号 :,函数体缩进。

def function_name(parameters):

"""可选的文档字符串"""

函数体代码

return 返回值 # 可选

eg

复制代码
def greet():
    """打印欢迎信息"""
    print("Hello, welcome to Python!")

# 调用函数
greet()
  • def greet()::def 是定义函数的关键字,greet 是函数名,空括号表示该函数不接受任何参数,冒号表示函数体开始。

  • """打印欢迎信息""":这是一个文档字符串(docstring),用三个双引号包围。它是对函数功能的说明,可以通过 help(greet) 或 greet.__doc__ 查看。虽然不是必需的,但强烈建议添加。

  • print("Hello, welcome to Python!"):这是函数体,缩进表示属于函数的一部分。当函数被调用时,这一行代码会被执行。

  • greet():调用函数,执行函数体内的代码。

2.2 带参数的函数

复制代码
def greet_person(name):
    """向指定的人打招呼"""
    print(f"Hello, {name}!")

greet_person("Alice")   # Hello, Alice!
  • def greet_person(name)::定义了一个形参 name,它将在函数内部作为变量使用。

  • print(f"Hello, {name}!"):函数体内使用了 name 变量,它的值由调用时传入。

  • greet_person("Alice"):调用时传入实参 "Alice",它会被赋值给形参 name,因此函数体内输出 Hello, Alice!。

2.3 带返回值的函数

使用 return 语句返回结果。

复制代码
def add(a, b):
    """返回两个数的和"""
    result = a + b
    return result

sum_val = add(3, 5)   # 返回 8
print(sum_val)

代码解析:

  • def add(a, b)::定义两个形参 a 和 b。

  • result = a + b:计算两个参数的和,赋值给局部变量 result。

  • return result:将 result 的值返回给调用者。函数执行到 return 语句时会立即结束,并将返回值传递给调用方。

  • sum_val = add(3, 5):调用 add 函数,实参 3 和 5 分别传给 a 和 b,函数返回 8,然后赋值给变量 sum_val。

  • print(sum_val):输出 8。

2.4 空函数(占位)

如果函数体还未实现,可以用 pass 占位。

复制代码
def not_ready():
    pass   # 稍后实现

代码解析:

  • def not_ready()::定义函数。

  • pass:是一个空语句,什么都不做。语法上需要一个语句,但逻辑上还未实现,用 pass 避免语法错误。


3. 函数的调用

调用函数就是使用函数名加上括号和实际参数。

复制代码
# 定义
def multiply(x, y):
    return x * y

# 调用
result = multiply(4, 5)
print(result)   # 20

代码解析:

  • def multiply(x, y)::定义乘法函数。

  • return x * y:返回两数乘积。

  • result = multiply(4, 5):调用函数,实参 4 对应 x,5 对应 y,返回值 20 存入 result。

  • print(result):输出 20。

调用时的细节:

  • 函数名后面必须跟括号,即使没有参数也要写 ()。

  • 实参会按照形参的位置一一对应(位置参数)。

  • 调用时传递的实参个数必须与形参个数匹配(除非有默认参数)。

4. 参数类型详解

4.1 位置参数(必须参数)

最普通的形式,调用时按顺序传递。

复制代码
def greet_with_default(name, greeting="Hello"):
    print(f"{greeting}, {name}!")

greet_with_default("Alice")           # Hello, Alice!
greet_with_default("Bob", "Hi")       # Hi, Bob!

代码解析:

  • greeting="Hello":为 greeting 参数指定默认值 "Hello"。调用时若不提供第二个参数,则使用默认值。

  • greet_with_default("Alice"):只传一个参数,greeting 使用默认值 "Hello",输出 Hello, Alice!。

  • greet_with_default("Bob", "Hi"):传入两个参数,greeting 被覆盖为 "Hi",输出 Hi, Bob!。

注意:默认参数必须放在非默认参数之后。

复制代码
# 错误写法
def wrong(a=1, b):   # SyntaxError
    pass

陷阱:默认参数的值只在函数定义时计算一次,因此不能使用可变对象作为默认值(如列表)。

复制代码
# 不推荐
def add_item(item, lst=[]):
    lst.append(item)
    return lst

print(add_item(1))   # [1]
print(add_item(2))   # [1, 2]   ← 同一个列表被重复使用

代码解析:

  • 因为默认参数 lst 在函数定义时被创建(一个空列表),之后每次调用若不提供 lst,都会使用同一个列表对象,导致累积。

  • 解决办法是使用 None 作为默认值,然后在函数内部创建新列表。

正确做法:

复制代码
def add_item(item, lst=None):
    if lst is None:
        lst = []
    lst.append(item)
    return lst

代码解析:

  • lst=None:默认值设为不可变对象 None。

  • if lst is None: lst = []:每次调用时若未传入列表,则新建一个空列表,保证了独立性。

4.3 关键字参数

调用时通过形参名指定实参,可以改变顺序。

复制代码
def describe_pet(name, species):
    print(f"{name} is a {species}")

describe_pet(species="cat", name="Tom")   # Tom is a cat

代码解析:

  • describe_pet(species="cat", name="Tom"):显式指定每个参数的名字,顺序可以与定义不同。这样调用时不会受位置影响,增强了可读性。

4.4 可变长度参数

  • *args:接收任意多个位置参数,打包成元组。

  • **kwargs:接收任意多个关键字参数,打包成字典。

    def sum_all(*args):
    return sum(args)

    print(sum_all(1, 2, 3, 4)) # 10

代码解析:

  • *args:收集所有传入的位置参数为一个元组,这里 args 是 (1,2,3,4)。

  • sum(args):内置函数 sum 对元组求和,返回 10。

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

    print_info(name="Alice", age=30, city="Paris")

代码解析:

  • **kwargs:收集所有传入的关键字参数为一个字典,这里 kwargs 是 {'name':'Alice','age':30,'city':'Paris'}。

  • 遍历字典并打印。

4.5 参数组合顺序

在函数定义中,参数的顺序必须是:

  1. 位置参数

  2. 默认参数

  3. *args

  4. 关键字参数(仅限 * 之后)

  5. **kwargs

    def complex_func(a, b=1, *args, c=2, **kwargs):
    pass

代码解析:

  • a 是普通位置参数。

  • b=1 是默认参数。

  • *args 接收多余的位置参数。

  • c=2 是仅限关键字参数(必须通过关键字传递)。

  • **kwargs 接收多余的关键字参数。


5. 返回值详解

5.1 单个返回值

复制代码
def square(x):
    return x ** 2

代码解析 :函数返回 x 的平方,返回后调用方可以接收。

5.2 多个返回值(本质是返回元组)

复制代码
def get_stats(numbers):
    return min(numbers), max(numbers), sum(numbers)/len(numbers)

low, high, avg = get_stats([1,2,3,4,5])
print(low, high, avg)   # 1 5 3.0

代码解析:

  • return min(...), max(...), avg(...):实际上返回了一个元组 (min, max, avg)。

  • 调用方通过 low, high, avg = ... 进行拆包,分别接收三个值。

5.3 return 语句省略时返回 None

复制代码
def do_nothing():
    pass

print(do_nothing())   # None

代码解析 :函数没有显式 return,默认返回 None。

5.4 return 提前退出函数

复制代码
def is_positive(n):
    if n > 0:
        return True
    return False

代码解析:

  • 如果 n > 0,执行 return True,函数立即结束,不会执行后面的 return False。

  • 否则执行 return False。这种写法可避免使用 else。


6. 作用域

6.1 局部变量与全局变量

  • 在函数内部赋值的变量是局部变量,只在函数内有效。

  • 在函数外部定义的变量是全局变量 ,可在函数内读取,但若要修改需用 global 关键字。

    x = 10 # 全局变量

    def func():
    global x # 声明要修改全局变量
    x = 20
    y = 5 # 局部变量

    func()
    print(x) # 20

代码解析:

  • x = 10:全局变量。

  • def func(): 内部 global x:告诉 Python 这里的 x 是全局变量,而不是创建局部变量。

  • x = 20:修改全局 x 的值为 20。

  • y = 5:未声明 global,因此是局部变量,函数外部无法访问。

  • 调用 func() 后,全局 x 变为 20。

注意 :避免过多使用 global,推荐通过参数传递和返回值来通信。

6.2 nonlocal 关键字(用于嵌套函数)

在内层函数中修改外层函数(非全局)的变量。

复制代码
def outer():
    count = 0
    def inner():
        nonlocal count
        count += 1
        return count
    return inner

counter = outer()
print(counter())   # 1
print(counter())   # 2

代码解析:

  • outer 函数中定义了局部变量 count 和内层函数 inner。

  • inner 中使用 nonlocal count 声明要修改的是外层函数 outer 的 count 变量,而不是创建一个新的局部变量。

  • count += 1 修改外层变量。

  • outer 返回 inner 函数对象,形成一个闭包。每次调用 counter() 都会增加并返回 count 的值。


7. 函数也是对象

在 Python 中,函数是一等公民,可以赋值给变量、作为参数传递、作为返回值。

复制代码
def add(a, b):
    return a + b

my_func = add       # 赋值
print(my_func(3, 4))   # 7

代码解析 :将函数 add 赋值给变量 my_func,my_func 现在指向同一个函数对象,可以像 add 一样调用。

复制代码
def apply(func, x, y):
    return func(x, y)

print(apply(add, 5, 6))   # 11

代码解析 :apply 函数接收一个函数作为参数 func,然后在内部调用它。这体现了高阶函数的特性。


8. 匿名函数(lambda)

lambda 表达式用于创建简单的、单表达式的匿名函数。

复制代码
square = lambda x: x ** 2
print(square(5))   # 25

代码解析:

  • lambda x: x ** 2 定义了一个匿名函数,等价于 def square(x): return x**2。

  • 但 lambda 只能包含一个表达式,不能包含语句。

    常用于 sort 的 key 参数

    pairs = [(1, 'one'), (2, 'two'), (3, 'three')]
    pairs.sort(key=lambda pair: pair[1]) # 按字符串排序

代码解析 :sort 的 key 参数接收一个函数,用于从每个元素中提取比较键。这里用 lambda 取每个元组的第二个元素(字符串)作为排序依据。

限制 :lambda 只能有一个表达式,不能包含语句(如 print、return 等)。


9. 递归函数

函数调用自身称为递归。需要明确的终止条件。

复制代码
def factorial(n):
    if n <= 1:
        return 1
    return n * factorial(n - 1)

print(factorial(5))   # 120

代码解析:

  • if n <= 1: return 1:递归的终止条件,防止无限递归。

  • return n * factorial(n-1):递归调用,每次减少 n 的值。

  • 调用过程:factorial(5) → 5 * factorial(4) → 5 * 4 * factorial(3) → ... → 5 * 4 * 3 * 2 * 1。

注意:Python 递归深度有限制(默认约 1000),深层递归建议改用循环。

10. 类型注解(Type Hints)

Python 3.5+ 支持类型注解,提高代码可读性(不强制检查)。

复制代码
def greet(name: str) -> str:
    return f"Hello, {name}"

代码解析:

  • name: str:表示参数 name 应为字符串类型。

  • -> str:表示返回值应为字符串类型。

  • 这些注解只是提示,不会在运行时检查类型错误。可以用 mypy 工具进行静态类型检查。


11. 常见内置函数示例

  • print():输出

  • len():返回长度

  • type():返回类型

  • input():读取用户输入

  • range():生成整数序列

  • sum()、max()、min() 等

这些内置函数无需定义,直接使用。

12.常见陷阱与最佳实践

陷阱 说明 解决方案
使用可变对象作为默认参数 函数多次调用共享同一对象 使用 None 并在函数内创建新对象
在函数内修改全局变量未声明 会创建同名局部变量 使用 global 或通过参数/返回值传递
混淆位置参数和关键字参数 调用时顺序错误 明确指定关键字参数名
递归深度过大导致栈溢出 递归超过系统限制 改用循环或增加 sys.setrecursionlimit
忘记 return 导致返回 None 预期有返回值但实际为 None 检查函数所有分支是否都有 return
lambda 内使用复杂逻辑 无法使用语句,代码难读 改用普通函数

感谢你的观看,期待我们下次再见!

相关推荐
andyweike15 小时前
php笔记
开发语言·笔记·php
LOVE️YOU15 小时前
Python 在定义函数时,究竟定义的是什么?
python
段一凡-华北理工大学16 小时前
大模型应用开发 100 天:Python + LLM 从入门到精通 day26~Prompt 调试与优化——A/B 测试与效果评估
windows·python·大模型·prompt·智能体·提示词工程·高炉智能化
Minecraft红客16 小时前
以撒的结合
python·游戏·电脑·娱乐
Circ.16 小时前
Python 调试 Litellm 本地大模型接口:模型列表与对话接口实操踩坑记录
开发语言·python
风早爽太16 小时前
用 ‌Render‌ 快速部署网站和常见问题解决
python·fastapi
现任明教教主~17 小时前
Thinkphp站群蜘蛛池SaaS系统YanyvSEO含多用户/积分/六大引擎计费/易支付对接
java·开发语言·spring
李航198318 小时前
给自己的图形引擎,配上了AI渲染,做设计真是太方便了
人工智能·python·计算机视觉·ai·ai编程
L@ncor18 小时前
第六章 框架开发实践 · 学习笔记(AutoGen / AgentScope / CAMEL / LangGraph)
python·框架·autogen·langgraph·agentscope
Zhou14113618 小时前
SpringSecurity_02_授权与高级功能
开发语言·python