飞翔飞翔
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
  • 学习路径
  • 第1章 Python简介

    • Python是什么
    • 安装与运行
    • 交互式解释器
    • 注释与编码规范
  • 第2章 变量与数据类型

    • 变量与对象
    • 整数 int
    • 浮点数 float
    • 复数 complex
    • 布尔值 bool
    • 字符串 str
    • 空值 None
    • 类型转换
  • 第3章 运算符与表达式

    • 算术运算符
    • 比较运算符
    • 赋值运算符
    • 逻辑运算符
    • 位运算符
    • 身份与成员运算符
    • 海象运算符
    • 运算符优先级
  • 第4章 流程控制

    • if 语句
    • if-else 语句
    • if-elif-else 语句
    • match-case 语句
    • 条件表达式(三元运算符)
    • while 循环
    • for 循环
    • range 函数
    • break 与 continue
    • 循环的 else 子句
    • pass 语句
  • 第5章 数据结构

    • 列表创建与索引
    • 列表方法
    • 列表推导式
    • 元组
    • 序列解包
    • 集合
    • 字典创建与访问
    • 字典方法
    • 字典推导式
    • range 对象
  • 第6章 函数

    • 定义函数
    • 位置参数与关键字参数
    • 默认参数
    • 可变参数
    • 解包实参
    • 函数返回值
    • lambda 表达式
    • 文档字符串与注解
    • 作用域与命名空间
    • global 与 nonlocal
  • 第7章 模块与包

    • 模块导入
    • 模块搜索路径
    • 包与相对导入
    • 标准库概览
  • 第8章 文件与输入输出

    • 文件读写
    • 上下文管理器
    • 字符串格式化
    • JSON 与 CSV
  • 第9章 面向对象

    • 类与对象
    • 方法
    • 实例变量与类变量
    • 私有变量
    • 继承
    • 多重继承
    • 魔术方法
    • 属性装饰器
    • 数据类 dataclass
  • 第10章 异常处理

    • 语法错误与异常
    • try-except
    • 异常链与 raise
    • 清理操作
    • 自定义异常
  • 第11章 迭代器与生成器

    • 迭代器协议
    • 生成器
    • 生成器表达式
    • 迭代工具
  • 第12章 高级特性

    • 装饰器
    • 函数式编程
  • 第13章 工程实践

    • 测试与调试
    • 代码质量
    • 虚拟环境

定义函数

函数是 Python 中最基本的代码组织单元。def 关键字会创建一个函数对象,并将其与当前命名空间中的名称绑定。理解函数定义背后的机制,比单纯记住语法更重要。

def 语句的完整语法

函数定义以 def 开头,后跟函数名、圆括号中的形参列表和冒号。函数体从新一行开始,必须缩进:

def greet(name):
    """向用户问好。"""
    print(f"你好,{name}!")

函数名遵循与变量相同的命名规则:只能包含字母、数字和下划线,不能以数字开头。按惯例,函数名使用小写加下划线(snake_case)。函数名可以与内置函数同名(如 def list():),但这会遮蔽内置名称,极不推荐。

函数定义是一条可执行语句。这意味着你可以在 if 分支、while 循环甚至另一个函数内部定义函数:

condition = True

if condition:
    def helper():
        return "条件为真时的辅助函数"
else:
    def helper():
        return "条件为假时的辅助函数"

print(helper())  # 条件为真时的辅助函数

函数对象与多重绑定

执行 def 语句时,Python 会创建一个函数对象(类型为 function),并将其地址赋给函数名。函数对象包含代码、文档字符串、默认参数值、注解等信息。函数名只是指向这个对象的引用,因此可以像任何其他对象一样被传递:

def square(x):
    return x * x

# 函数对象可以赋值给其他变量
f = square
print(f(5))        # 25
print(f is square) # True

# 可以放入列表、字典等容器中
funcs = [square, abs, len]
print(funcs[0](3))  # 9

# 可以作为其他函数的参数
def apply_twice(func, value):
    return func(func(value))

print(apply_twice(square, 2))  # 16

函数对象有一个 __name__ 属性,记录定义时的名称:

print(square.__name__)  # 'square'
f = square
print(f.__name__)       # 仍然是 'square'

函数命名空间与调用机制

每次调用函数时,Python 都会创建一个新的局部命名空间(局部符号表)。函数内部的所有变量赋值都进入这个局部命名空间;引用变量时,解释器按 LEGB 规则查找:先局部、再外层函数局部、再全局、最后内置。

x = "全局变量"

def demo():
    y = "局部变量"      # y 进入 demo 的局部命名空间
    print(x)            # x 不在局部,去全局找,输出"全局变量"
    print(y)            # y 在局部,输出"局部变量"

demo()
# print(y)  # NameError: name 'y' is not defined

实参传递的本质是对象引用传递:调用时,实参对象的引用被复制到被调用函数的局部符号表中。如果实参是可变对象(如列表、字典),函数内部通过引用修改对象内容,调用者会看到变化;如果实参是不可变对象(如整数、字符串),函数内部重新赋值只会改变局部引用,不影响外部。

def append_item(lst, item):
    lst.append(item)    # 原地修改可变对象,外部可见

def rebind_list(lst):
    lst = [99]          # 局部变量重新绑定,外部不可见

my_list = [1, 2]
append_item(my_list, 3)
print(my_list)          # [1, 2, 3]

rebind_list(my_list)
print(my_list)          # [1, 2, 3],未被改变

无返回值与 None

Python 函数始终有返回值。没有 return 语句,或 return 后面没有表达式时,函数返回 None。None 是内置名称,表示"什么都没有",类型为 NoneType。

def no_return():
    print("执行完毕")

result = no_return()
print(result)           # None
print(result is None)   # True

def explicit_none():
    return

print(explicit_none())  # None

初学者常犯的错误是把 print 和 return 混淆。print 向标准输出写内容,但返回 None;return 把值传回调用处。

def wrong():
    print(42)   # 只是打印,不返回

def right():
    return 42   # 把 42 传回调用处

x = wrong()     # 终端显示 42,但 x 是 None
y = right()     # y 是 42

函数定义的执行时机

函数体在定义时不会执行,只在调用时执行。但函数定义行中的默认参数表达式会在定义时求值:

i = 5
def f(arg=i):       # 定义时 i 是 5,默认值被固定为 5
    print(arg)

i = 6
f()                 # 输出 5,不是 6

这个特性对可变默认参数有深远影响,详见《默认参数》文档。

常见错误

函数体未缩进会报 IndentationError:

def broken():
print("未缩进")   # IndentationError

在 return 后写不可达代码会触发警告(但不会报错):

def unreachable(x):
    return x * 2
    print("这行永远不会执行")   # 语法上合法,逻辑上无意义

忘记括号会把函数对象本身当作返回值,而不是调用结果:

def get_value():
    return 42

print(get_value)    # <function get_value at 0x...>
print(get_value())  # 42

小结

def 创建函数对象并绑定名称;调用时新建局部命名空间;实参按对象引用传递;无 return 时返回 None。理解这些机制,是掌握 Python 函数编程的第一步。

下一页
位置参数与关键字参数