Skip to content

Python 快速指南

Python 是一种高级的、解释型的、交互式的、面向对象的脚本语言。它强调代码的可读性,其显著特点是使用了重要的缩进。

  • 解释型(Interpreted):Python 程序在运行时由解释器处理。在执行程序之前,你无需编译。
  • 交互式(Interactive):你可以直接与解释器交互,编写和测试代码片段。
  • 面向对象(Object-Oriented):Python 支持面向对象编程,允许围绕对象构建代码结构。
  • 对初学者友好(Beginner-Friendly):Python 语法简单易学,是初学者学习编程的绝佳语言。

Python 由 Guido van Rossum 创建,于 1991 年首次发布。其设计哲学强调代码的可读性,其语法允许程序员用比 C++ 或 Java 等语言更少的代码行来表达概念。

Python 的主要特点包括:

  • 易学易读:清晰的语法提高了可读性,降低了程序维护成本。
  • 易于维护:Python 的成功部分归功于其对可读性和简洁性的关注。
  • 广泛的标准库:Python 的“内置电池(batteries included)”哲学提供了用于许多常见任务的模块。
  • 交互模式:允许快速测试和调试。
  • 可移植:Python 代码无需修改即可在 Windows、macOS、Linux 和 Unix 等各种平台运行。
  • 可扩展:你可以用 C 或 C++ 等语言编写低级模块添加到 Python 解释器中。
  • 数据库:Python 提供了与所有主要商业数据库的接口。
  • GUI 编程:支持创建可移植到许多系统调用、库和窗口系统的 GUI(图形用户界面)应用程序。
  • 可伸缩:与 shell 脚本相比,Python 为大型程序提供了更好的结构和支持。
  • 强大的社区和生态系统:庞大活跃的社区以及丰富的 Python 包索引(PyPI)提供了无数第三方模块。

最新的源代码、二进制文件、文档、新闻等都可在 Python 官方网站获取:

Python 官方网站:https://www.python.org/

你可以为你的操作系统下载 Python,并访问各种格式的完整文档。

Python 文档网站:https://docs.python.org/3/

现代 Python 开发强烈依赖包管理和虚拟环境。pip 是标准的包安装器,而 venv 是创建独立环境的标准工具:

  • 安装包:python -m pip install <package_name>
  • 创建虚拟环境:python -m venv myenv
  • 激活环境(Linux/macOS):source myenv/bin/activate
  • 激活环境(Windows):myenv\Scripts\activate

不传递脚本文件直接调用解释器会启动交互会话:

$ python
Python 3.10.4 (main, Mar 31 2022, 08:41:55) [GCC 7.5.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

在 Python 提示符 (>>>) 后输入以下命令并按 Enter 键:

>>> print("Hello, Python!")

这将产生以下结果:

Hello, Python!

或者,将你的代码保存到文件(例如 hello.py)中,然后从终端运行:

hello.py
print("Hello, Python!")
$ python hello.py

输出:

Hello, Python!

Python 标识符是用于识别变量、函数、类、模块或其他对象的名称。标识符以字母 (A-Z 或 a-z) 或下划线 (_) 开头,后跟零个或多个字母、下划线和数字 (0-9)。

Python 不允许在标识符中使用 @、 $ 和 % 等标点符号。Python 是区分大小写的,这意味着 MyVariable 和 myvariable 是不同的标识符。

常见的标识符命名约定 (PEP 8):

  • 类名以大写字母开头(例如 MyClass)。
  • 函数名和变量名通常使用小写字母和下划线分隔单词(snake_case 命名法,例如 my_variable、calculate_sum)。
  • 常量通常用全大写字母书写(例如 MAX_CONNECTIONS)。
  • 标识符以一个前导下划线开头(例如 _internal_value)通常表示它仅用于内部使用(一个弱的“私有”指示器)。
  • 标识符以两个前导下划线开头(例如 __strong_private)会触发名称修饰(name mangling),使得从类外部难以直接访问。
  • 以两个下划线开头和结尾的标识符(例如 __init__、__str__)是语言定义的特殊“dunder”(双下划线)方法或属性。

以下单词在 Python 中是保留字,不能用作标识符(变量名、函数名等)。

| False | await | else | import | pass | | None | break | except | in | raise | | True | class | finally | is | return | | and | continue | for | lambda | try | | as | def | from | nonlocal | while | | assert | del | global | not | with | | async | elif | if | or | yield |

Python 使用缩进来定义代码块(例如循环、函数、类和条件语句),这与许多使用花括号 {} 的其他语言不同。这强制执行了一种可读的代码风格。

标准约定是每个缩进级别使用 四个空格。同一代码块内的所有语句必须具有相同的缩进。

正确的缩进:

if True:
print("Condition is True")
# 这也是 'if' 块的一部分
print("Still inside the block") # 仍在块内
else:
print("Condition is False")
print("This is outside the if/else block") # 这在 if/else 块外部

不正确的缩进(将导致 IndentationError):

if True:
print("Answer is True")
print("This line has wrong indentation") # 错误!
else:
print("Answer is False") # 如果不一致也可能错误

Python 中的语句通常以换行符结束。但是,你可以使用行继续符 (\) 将语句延续到下一行:

total = item_one + \
item_two + \
item_three

包含在 []、{} 或 () 中的语句不需要使用行继续符:

days = ['Monday', 'Tuesday', 'Wednesday',
'Thursday', 'Friday']
my_tuple = (1, 2, 3,
4, 5)
my_dict = {'key1': 'value1',
'key2': 'value2'}

Python 接受单引号 (')、双引号 (") 和三重引号 (''' 或 """) 来表示字符串字面量。单引号和双引号的作用完全相同。字符串必须由相同类型的引号开始和结束。

三重引号允许字符串跨越多行,并按字面值包含换行符:

word = 'word'
sentence = "This is a sentence."
paragraph = """This is a paragraph.
It is made up of multiple lines and sentences.
Newlines are preserved."""
print(word)
print(sentence)
print(paragraph)

注释以井号 (#) 开头,并延续到物理行的末尾。Python 解释器会忽略注释。它们用于解释代码。

#!/usr/bin/env python3
# 这是一个整行注释
print("Hello, Python!") # 这是一个行内注释
# 另一个注释
# 跨越多行。

这将产生以下结果:

Hello, Python!

多行注释也可以通过使用三重引号字符串来近似实现,尽管这些在技术上是字符串字面量,而不是真正的注释。它们通常用于文档字符串(docstrings)。

"""这通常用作多行注释
或文档字符串 (docstring)。
它实际上是一个字符串字面量,如果未赋值则会被忽略。
"""
def my_function():
"""这是一个解释函数的文档字符串。"""
pass

空行(只包含空白字符,可能带有注释)会被 Python 忽略。它们用于通过分隔代码的逻辑块来提高代码的可读性。

在交互式解释器中,有时需要一个空的物理行来结束多行语句(例如,在定义函数或类之后)。

分号 (;) 允许在单行上书写多个语句,前提是这些语句都不开始一个新的代码块。通常不鼓励这样做,因为它会降低可读性。

import sys; x = 'foo'; sys.stdout.write(x + '\n') # 可以工作,但可读性较差

推荐一行只写一个语句:

import sys
x = 'foo'
sys.stdout.write(x + '\n')

在控制结构(如 if、while、def、class)下形成单个代码块的一组语句在 Python 中称为“套件”(suite)。

复合语句由以冒号 (:) 结尾的头部行和其后缩进的套件组成。

if expression:
# 这是 'if' 块的套件
statement1
statement2
elif expression:
# 'elif' 块的套件
statement3
else:
# 'else' 块的套件
statement4

变量是引用存储在内存中值的名称。创建变量时,你将一个名称与一个值关联起来。

Python 使用动态类型,这意味着你不需要显式声明变量的类型。类型是从赋给它的值推断出来的。解释器根据数据类型分配内存。

赋值运算符 (=) 用于为变量赋值。变量名在左边,值在右边。

counter = 100 # 一个整数赋值
miles = 1000.0 # 一个浮点数赋值
name = "Alice" # 一个字符串赋值
is_active = True # 一个布尔值赋值
print(counter)
print(miles)
print(name)
print(is_active)

也可以进行多重赋值:

a = b = c = 1 # 将 1 赋给 a, b 和 c
x, y, z = 1, 2, "hello" # 将多个值赋给多个变量
print(a, b, c)
print(x, y, z)

Python 有几种内置数据类型。主要类别有:

  • 数值类型:int(整数)、float(浮点数)、complex(复数)。注意:Python 3 的 int 可以处理任意大的整数。
  • 布尔类型:bool(True 或 False)。
  • 序列类型:str(字符串)、list(可变序列)、tuple(不可变序列)。
  • 集合类型:set(无序的唯一项集合)、frozenset(不可变版本的 set)。
  • 映射类型:dict(字典,键值对)。
  • None 类型:NoneType(表示值的缺失,只有一个值:None)。

你可以使用 type() 函数检查变量的类型:

num = 10
print(type(num)) # 输出: <class 'int'>
pi = 3.14
print(type(pi)) # 输出: <class 'float'>
message = "Hi"
print(type(message)) # 输出: <class 'str'>

当你赋值一个数值时,就会创建数字对象。

var1 = 1
var2 = 10.5
var3 = 3 + 4j # 复数
print(var1, type(var1))
print(var2, type(var2))
print(var3, type(var3))

Python 支持标准数值类型:

  • int:任意大小的有符号整数(例如 10、-786、0、12345678901234567890)。
  • float:浮点实数(例如 15.20、-21.9、3.14e-10)。
  • complex:带实部和虚部的复数(例如 3.14j、45.j、9.322e-36j、3+4j)。

Python 3 中的字符串是 Unicode 字符序列,用单引号或双引号括起来。它们是不可变的,这意味着创建后不能更改其内容。

my_str = 'Hello World!'
print(my_str) # 打印完整字符串: Hello World!
print(my_str[0]) # 打印第一个字符: H
print(my_str[6:11]) # 打印从索引 6 开始到(但不包括)索引 11 的字符: World
print(my_str[6:]) # 打印从索引 6 开始的字符串: World!
print(my_str * 2) # 打印字符串两次: Hello World!Hello World!
print(my_str + " TEST") # 打印连接后的字符串: Hello World! TEST
# 尝试更改字符将导致错误:
# my_str[0] = 'J' # TypeError: 'str' object does not support item assignment

现代字符串格式化使用 f-string (Python 3.6+):

name = "Alice"
age = 30
print(f"My name is {name} and I am {age} years old.")
# 输出: My name is Alice and I am 30 years old.

列表是多用途的、可变(changeable)的序列,用方括号 [] 括起来。项目之间用逗号分隔,并且可以是不同的数据类型。

my_list = ['abcd', 786, 2.23, 'john', 70.2]
tiny_list = [123, 'john']
print(my_list) # 打印完整列表: ['abcd', 786, 2.23, 'john', 70.2]
print(my_list[0]) # 打印第一个元素: abcd
print(my_list[1:3]) # 打印从索引 1 到(但不包括)索引 3 的元素: [786, 2.23]
print(my_list[2:]) # 打印从索引 2 开始的元素: [2.23, 'john', 70.2]
print(tiny_list * 2) # 打印列表两次: [123, 'john', 123, 'john']
print(my_list + tiny_list) # 打印连接后的列表: ['abcd', 786, 2.23, 'john', 70.2, 123, 'john']
# 列表是可变的
my_list[2] = 'updated'
print(my_list) # 输出: ['abcd', 786, 'updated', 'john', 70.2]

元组是不可变(unchangeable)的序列,用圆括号 () 括起来。项目之间用逗号分隔。

元组常用于固定项目集合,并且可以作为字典的键(与列表不同)。

my_tuple = ('abcd', 786, 2.23, 'john', 70.2)
tiny_tuple = (123, 'john')
print(my_tuple) # 打印完整元组: ('abcd', 786, 2.23, 'john', 70.2)
print(my_tuple[0]) # 打印第一个元素: abcd
print(my_tuple[1:3]) # 打印从索引 1 到(但不包括)索引 3 的元素: (786, 2.23)
print(my_tuple[2:]) # 打印从索引 2 开始的元素: (2.23, 'john', 70.2)
print(tiny_tuple * 2) # 打印元组两次: (123, 'john', 123, 'john')
print(my_tuple + tiny_tuple) # 打印连接后的元组: ('abcd', 786, 2.23, 'john', 70.2, 123, 'john')
# 尝试更改元素将导致错误:
# my_tuple[0] = 'xyz' # TypeError: 'tuple' object does not support item assignment
# 单元素元组需要加逗号:
single_item_tuple = (50,) # 这是一个元组
not_a_tuple = (50) # 这只是圆括号中的整数 50

字典 (dict) 是无序的(Python < 3.7)或有序的(Python 3.7+)键值对集合,用花括号 {} 括起来。键必须唯一且不可变(如字符串、数字或元组)。值可以是任何数据类型。

my_dict = {'name': 'john', 'code': 6734, 'dept': 'sales'}
print(my_dict['name']) # 打印键 'name' 对应的值: john
print(my_dict['code']) # 打印键 'code' 对应的值: 6734
# print(my_dict[2]) # 错误!访问字典使用键,而不是整数索引,除非键本身是整数。
print(my_dict) # 打印完整字典: {'name': 'john', 'code': 6734, 'dept': 'sales'}
print(my_dict.keys()) # 打印所有键的视图: dict_keys(['name', 'code', 'dept'])
print(my_dict.values()) # 打印所有值的视图: dict_values(['john', 6734, 'sales'])
print(my_dict.items()) # 打印键值对的视图: dict_items([('name', 'john'), ('code', 6734), ('dept', 'sales')])
# 添加或更新项
my_dict['age'] = 35 # 添加新的键值对
my_dict['dept'] = 'IT' # 更新现有键 'dept' 的值
print(my_dict)

运算符对变量和值执行操作。Python 包括算术、比较、赋值、逻辑、位、成员关系和身份运算符。

Operator名称描述Example
+加法Adds values on either sidea + b
-减法从左操作数中减去右操作数a - b
*乘法乘以值a * b
/真除法将左操作数除以右操作数,结果始终为浮点数b / a (e.g., 10 / 4 is 2.5)
%取模返回除法的余数b % a
**幂运算将左操作数提升到右操作数的幂a**b
//整除进行除法并向下取整到最接近的整数b // a (e.g., 10 // 4 is 2, -10 // 4 is -3)
==等于检查值是否相等a == b
!=不等于检查值是否不相等a != b
>大于检查左操作数是否大于右操作数a > b
<小于检查左操作数是否小于右操作数a < b
>=大于或等于检查左操作数是否大于或等于右操作数a >= b
<=小于或等于检查左操作数是否小于或等于右操作数a <= b
=赋值将右操作数的值赋给左操作数c = a + b
+=加法赋值将右操作数加到左操作数,并将结果赋给左操作数c += a (same as c = c + a)
-=减法赋值将右操作数从左操作数中减去,并将结果赋给左操作数c -= a
*=乘法赋值将左操作数乘以右操作数,并将结果赋给左操作数c *= a
/=除法赋值将左操作数除以右操作数,并将结果(浮点数)赋给左操作数c /= a
%=取模赋值对左操作数取模,并将结果赋给左操作数c %= a
**=幂赋值将左操作数提升到右操作数的幂,并将结果赋给左操作数c **= a
//=整除赋值执行整除,并将结果赋给左操作数c //= a
&按位与执行按位与操作a & b
|按位或执行按位或操作a | b
^按位异或执行按位异或操作a ^ b
~按位取反翻转位(一元运算符)~a
<<按位左移将位左移a << 2
>>按位右移将位右移a >> 2
and逻辑与如果两个操作数都为 true 则为 Truea > 5 and b < 10
or逻辑或如果至少一个操作数为 true 则为 Truea > 5 or b < 10
not逻辑非反转逻辑状态not (a > 5)
in成员关系如果在序列中找到值则为 Truex in my_list
not in成员关系如果在序列中未找到值则为 Truex not in my_list
is身份如果两个变量指向内存中的同一个对象则为 Truex is y
is not身份如果变量指向不同的对象则为 Truex is not y

注意:<> 运算符在 Python 3 中已移除;请改用 !=。

运算符按照特定的顺序(优先级)进行求值。使用圆括号 () 可以改变优先级或提高清晰度。

Operator描述
()圆括号(最高优先级)
f(args...), x[index], x[index:index], x.attribute函数调用、切片、下标、属性引用
await xawait 表达式
**幂运算(右结合)
+x, -x, ~x正号、负号、按位非
*, /, //, %乘法、除法、整除、取模
+, -加法和减法
<<, >>按位移位
&按位与
^按位异或
|按位或
in, not in, is, is not, <, <=, >, >=, !=, ==比较,包括成员关系和身份测试
not x布尔非
and布尔与
or布尔或
if else条件表达式
lambdaLambda 表达式
:=赋值表达式(海象运算符,Python 3.8+)

注意:同一框中的运算符从左到右求值,除了幂运算 (**) 是右结合的。

条件语句允许根据条件是真还是假来执行代码。

只有当条件为真时,才执行代码块。

if expression:
statement(s) # 语句

如果条件为真,则执行一个代码块;如果为假,则执行另一个代码块。

if expression:
statement(s)_if_true # 条件为真时执行的语句
else:
statement(s)_if_false # 条件为假时执行的语句

按顺序检查多个条件。elif 是 ‘else if’ 的缩写。

if expression1:
statement(s)_1 # 语句 1
elif expression2:
statement(s)_2 # 语句 2
elif expression3:
statement(s)_3 # 语句 3
# ... 更多 elif 块 ...
else:
statement(s)_else # else 语句

你可以将 if、elif 或 else 语句放在其他条件块内部。

if expression1:
# 外层 if 块
if expression2:
# 内层 if 块
statement(s)_A # 语句 A
else:
# 内层 else 块
statement(s)_B # 语句 B
else:
# 外层 else 块
statement(s)_C # 语句 C

循环重复执行一个代码块。

只要条件保持为真,就重复执行一个代码块。

while expression:
statement(s) # 语句

示例:

count = 0
while count < 5:
print(f"Count is: {count}")
count += 1 # 重要:更新计数器以避免无限循环
print("Loop finished") # 循环结束

请注意!如果 while 循环中的条件永远不会变为假,它将永远运行(无限循环)。按 Ctrl+C 可以中断它。有时无限循环是故意的(例如,服务器等待连接时),通常使用 break 在特定条件下退出。

遍历任何序列(如列表、元组、字符串或字典的键/值)或其他可迭代对象的项目。

for item in sequence:
statements(s) # 语句
fruits = ['banana', 'apple', 'mango']
for fruit in fruits:
print(f"Current fruit: {fruit}") # 当前水果: {fruit}
print("Goodbye!") # 再见!

range() 函数生成一个数字序列,对于循环特定次数非常有用。

# range(stop) - 从 0 开始到 stop (但不包括 stop)
for i in range(5):
print(i) # 输出: 0, 1, 2, 3, 4
# range(start, stop) - 从 start 开始到 stop (但不包括 stop)
for i in range(2, 6):
print(i) # 输出: 2, 3, 4, 5
# range(start, stop, step) - 按 step 递增
for i in range(0, 10, 2):
print(i) # 输出: 0, 2, 4, 6, 8

你可以结合 range() 和 len() 使用索引进行迭代,尽管直接遍历项目通常更“Pythonic”(符合 Python 风格)。

fruits = ['banana', 'apple', 'mango']
for index in range(len(fruits)):
print(f"Index: {index}, Fruit: {fruits[index]}")
# 使用 enumerate() 的更 Pythonic 的方式:
for index, fruit in enumerate(fruits):
print(f"Index: {index}, Fruit: {fruit}")

提前终止当前循环,并将控制转移到紧跟在循环后面的语句。

for letter in 'Python':
if letter == 'h':
break
print(f'Current Letter: {letter}')
# 输出: Current Letter: P, Current Letter: y, Current Letter: t
num = 10
while num > 0:
print(f'Current variable value: {num}')
num -= 1
if num == 5:
break # 当 num 变为 5 时退出循环
print("Goodbye!") # 再见!

跳过当前循环迭代中剩余的代码,并进入下一次迭代。

for letter in 'Python':
if letter == 'h':
continue # 跳过 'h'
print(f'Current Letter: {letter}')
# 输出: Current Letter: P, Current Letter: y, Current Letter: t, Current Letter: o, Current Letter: n
num = 10
while num > 0:
num -= 1
if num == 5:
continue # 当 num 为 5 时跳过打印
print(f'Current variable value: {num}')
print("Goodbye!") # 再见!

Python 循环可以有一个可选的 else 子句。else 块只有在循环正常完成(即不是由 break 语句终止)时才会执行。

for i in range(5):
print(i)
# if i == 3: break # 取消注释此行将跳过 else 块
else:
print("Loop finished normally") # 循环正常结束
count = 0
while count < 3:
print(count)
count += 1
# if count == 2: break # 取消注释此行将跳过 else 块
else:
print("While loop finished normally") # while 循环正常结束

pass 语句是一个空操作;执行时什么也不发生。它在语法需要语句但不需要执行任何操作的地方充当占位符。

在开发过程中或在抽象类中,它对于空 的代码块很有用。

def my_empty_function():
pass # 避免空函数体导致的 SyntaxError
class MyEmptyClass:
pass
for letter in 'Python':
if letter == 'h':
pass # 占位符,稍后可能添加代码
print('This is pass block for h')
print(f'Current Letter: {letter}')
print("Goodbye!") # 再见!

函数是执行特定任务的可重用代码块。它们有助于组织代码、提高代码可读性并减少冗余。

在 Python 中定义函数的规则:

  • 函数块以关键字 def 开头,后跟函数名和圆括号 ()。函数名遵循标准的标识符规则。
  • 输入参数(arguments)放在圆括号内。参数是可选的。
  • 函数头部行以冒号 (:) 结尾。
  • 函数内的代码块(套件)必须缩进。
  • 可选的文档字符串(docstring),通常是用三重引号括起来的字符串,可以是函数体的第一个语句。它解释了函数的功能。
  • return 语句退出函数,并可选地将一个值发送回调用者。如果省略 return 或不带表达式使用,函数将返回 None。
def function_name(parameters):
"""可选的文档字符串,解释函数的功能。"""
# 函数套件(缩进代码块)
statement1
statement2
# ...
return [expression] # 可选的返回值

默认情况下,参数按位置传递,与其定义顺序匹配。

一个接受字符串并打印的简单函数:

def print_message(message):
"""将传入的字符串打印到控制台。"""
print(message)
# 没有显式 return 语句意味着它返回 None

一个返回值函数:

def add(a, b):
"""返回两个数字的和。"""
return a + b

Python 3 允许为函数签名添加类型提示 (PEP 484),以提高代码清晰度并支持工具(如静态分析)。

def greet(name: str) -> str:
"""为给定的名称返回一个问候字符串。"""
return f"Hello, {name}!"
def calculate_area(length: float, width: float) -> float:
"""计算矩形的面积。"""
return length * width

定义函数并不会执行它。你需要通过函数名后跟圆括号 () 来“调用”函数,并在括号内传入任何必需的参数。

使用上面定义的函数的示例:

# 函数定义在此处
def print_message(message: str):
"""打印传入的字符串。"""
print(message)
def add(a: int, b: int) -> int:
"""返回两个整数的和。"""
return a + b
# 现在调用函数
print_message("Calling the print_message function!") # 调用 print_message 函数!
print_message("Second call to the same function.") # 第二次调用同一个函数。
sum_result = add(5, 3)
print(f"The sum is: {sum_result}") # 和是: {sum_result}

这将产生以下结果:

Calling the print_message function!
Second call to the same function.
The sum is: 8

模块是包含 Python 定义和语句(函数、类、变量)的 Python 文件(.py)。它们允许你对代码进行逻辑组织,并在不同的程序中重用代码。

将相关的代码分组到模块中,可以使项目更容易理解、维护和扩展。

创建一个名为 my_module.py 的文件,内容如下:

my_module.py
def greet(name: str):
"""打印问候语。"""
print(f"Hello, {name} from my_module!")
PI = 3.14159

要在另一个 Python 脚本中使用模块中的定义,你需要使用 import 语句。

module_name.member
# 选项 1: 导入整个模块
import module_name
# 选项 2: 从模块中导入特定名称
from module_name import name1, name2
# 直接按名称访问成员: name1
# 选项 3: 导入所有名称(由于命名空间污染,通常不推荐)
# from module_name import *
# 选项 4: 导入并使用别名
import module_name as alias
from module_name import long_name as short_name

当 Python 遇到 import 语句时,它会在特定的目录列表 (sys.path) 中搜索模块,包括当前脚本所在的目录和标准库位置。模块在每个解释器会话中只加载并执行一次。

在同一目录下创建另一个文件,例如 main_script.py:

main_script.py
# 导入整个模块
import my_module
# 导入特定名称
from my_module import PI
# 使用模块名调用函数
my_module.greet("Alice")
# 直接访问常量(因为它是被特定导入的)
print(f"The value of PI is approximately: {PI}") # PI 的值约为: {PI}

运行 main_script.py 会产生:

Hello, Alice from my_module!
The value of PI is approximately: 3.14159

包是一种使用“点分模块名”来组织 Python 模块命名空间的方式。包本质上是一个包含 Python 模块和一个特殊的 __init__.py 文件(可以为空)的目录,用于将该目录标记为一个包。

示例结构:
my_package/
__init__.py
module1.py
module2.py
sub_package/
__init__.py
module3.py

你可以像这样从包中导入:

import my_package.module1
from my_package.sub_package import module3
from my_package.module2 import specific_function

要读取或写入文件,首先需要使用内置的 open() 函数打开它们。推荐的方式是使用 with 语句,它会自动处理文件的关闭,即使发生错误也是如此。

with open(file_path, mode='r', encoding=None) as file_object:
# 对 file_object 执行操作(读、写等)
# 在退出 'with' 块时文件会自动关闭
pass # File is automatically closed when exiting the 'with' block

参数详情:

  • file_path:一个字符串,包含文件的路径。
  • mode:指定打开文件的目的(可选,默认为 'r'):
  • 'r':读取(默认)。如果文件不存在则出错。
  • 'w':写入。如果文件不存在则创建,如果文件存在则清空内容(截断)。
  • 'a':追加。如果文件不存在则创建,将数据添加到文件末尾。
  • 'x':独占创建。创建文件,如果文件已存在则出错。
  • 'b':二进制模式(附加到其他模式,例如 'rb'、'wb')。用于非文本文件。
  • 't':文本模式(默认,附加为 'rt'、'wt')。
  • '+':更新(读写,例如 'r+'、'w+')。
  • encoding:用于文本文件的编码(可选,但为了可移植性强烈推荐)。常见值:'utf-8'、'ascii'、'latin-1'。如果省略,则使用系统默认编码,这可能导致错误。
file_path = "my_file.txt"
# 写入文本到文件(覆盖现有内容或创建新文件)
try:
with open(file_path, 'w', encoding='utf-8') as f:
print(f"Name of the file: {f.name}") # 文件名: {f.name}
print(f"Closed or not : {f.closed}") # 是否已关闭 : {f.closed}
print(f"Opening mode : {f.mode}") # 打开模式 : {f.mode}
print(f"Encoding : {f.encoding}") # 编码 : {f.encoding}
f.write("This is the first line.\n") # 这是一个示例行。\n
f.write("This is the second line.\n")
# 退出 'with' 块后
print(f"\nFile closed now? {f.closed}") # 文件现在关闭了吗?{f.closed} # 注意:f 仍然被定义,但文件已关闭
except IOError as e:
print(f"Error opening or writing file: {e}") # 打开或写入文件错误: {e}

这将产生类似以下结果:

Name of the file: sample.txt
Closed or not : False
Opening mode : w
Encoding : utf-8
File closed now? True

close() 方法(以及为何 with 更佳)

Section titled “close() 方法(以及为何 with 更佳)”

文件对象有一个 close() 方法。如果你不使用 with 语句打开文件,则必须显式调用 close() 以确保数据写入磁盘并释放资源。然而,忘记关闭或在关闭前遇到错误可能导致问题。

手动关闭(不太推荐):

# 手动打开/关闭 - 如果可能请避免
f = None # 初始化为 None
try:
f = open("old_style.txt", "w", encoding="utf-8")
print(f"File name: {f.name}") # 文件名: {f.name}
f.write("Manual close example.\n") # 手动关闭示例。\n
finally:
if f:
f.close() # 必须确保 close() 被调用
print("File closed manually.") # 文件已手动关闭。

在现代 Python 中,使用 with 语句是标准且最安全的做法。

文件对象提供了读写数据的方法。

将字符串(文本模式)或字节(二进制模式)写入文件。它不会自动添加换行符 (\n)。返回写入的字符/字节数。

file_object.write(data)
#!/usr/bin/env python3
file_path = "output.txt"
try:
with open(file_path, "w", encoding="utf-8") as f:
num_chars = f.write("Python is a great language.\n")
print(f"Wrote {num_chars} characters.") # 写入了 {num_chars} 个字符。
f.write("Yes, it's great!!\n")
print(f"Successfully wrote to {file_path}") # 成功写入到 {file_path}
except IOError as e:
print(f"Error writing file: {e}") # 写入文件错误: {e}
# output.txt 的内容将是:
# Python is a great language.
# Yes, it's great!!

从文件读取数据。文本模式下读取字符;二进制模式下读取字节。

file_object.read(size=-1)

这里,size 是可选的要读取的字符/字节数。如果省略或为负,则读取到文件末尾。

示例(使用上面创建的 output.txt)

Section titled “示例(使用上面创建的 output.txt)”
#!/usr/bin/env python3
file_path = "output.txt"
try:
with open(file_path, "r", encoding="utf-8") as f:
# 读取前 10 个字符
first_part = f.read(10)
print(f"First 10 chars: '{first_part}'") # 前 10 个字符: '{first_part}'
# 读取文件的其余部分
rest_of_file = f.read()
print(f"Rest of file: '{rest_of_file}'") # 文件的其余部分: '{rest_of_file}'
print("\nReading entire file at once:") # 一次性读取整个文件:
with open(file_path, "r", encoding="utf-8") as f:
all_content = f.read()
print(f"'{all_content}'") # '{all_content}'
except FileNotFoundError:
print(f"Error: File '{file_path}' not found.") # 错误:未找到文件 '{file_path}'。
except IOError as e:
print(f"Error reading file: {e}") # 读取文件错误: {e}

这将产生以下结果:

First 10 chars: 'Python is '
Rest of file: 'a great language.\nYes, it's great!!\n'
Reading entire file at once:
'Python is a great language.\nYes, it's great!!\n'
  • readline():读取一行,包括末尾的 \n(或直到文件末尾 EOF)。
  • readlines():将所有行读取到一个字符串列表中,每行都包含其 \n。
print("\nReading with readline():") # 使用 readline() 读取:
try:
with open(file_path, "r", encoding="utf-8") as f:
line1 = f.readline()
line2 = f.readline()
print(f"Line 1: {line1.strip()}") # 第 1 行: {line1.strip()} # .strip() 移除开头/结尾的空白字符
print(f"Line 2: {line2.strip()}") # 第 2 行: {line2.strip()}
except FileNotFoundError:
print(f"Error: File '{file_path}' not found.") # 错误:未找到文件 '{file_path}'。
except IOError as e:
print(f"Error reading file: {e}") # 读取文件错误: {e}

tell():返回文件指针的当前位置(从文件开头的字节偏移量)。

seek(offset, whence=0):移动文件指针。offset 是要移动的字节数。whence 确定参考点:

  • 0(默认):从文件开头算起的绝对位置。
  • 1:相对于当前指针位置的相对位置。
  • 2:相对于文件末尾的相对位置(offset 通常为负数)。
#!/usr/bin/env python3
file_path = "output.txt"
try:
with open(file_path, "r+", encoding="utf-8") as f: # 打开文件进行读写
# 读取前 10 个字符
str_data = f.read(10)
print(f"Read String is : '{str_data}'") # 读取的字符串是 : '{str_data}'
# 检查当前位置
position = f.tell()
print(f"Current file position : {position}") # 当前文件位置 : {position}
# 将指针重新定位到开头
f.seek(0, 0)
str_data = f.read(10) # 再次读取
print(f"Again read String is : '{str_data}'") # 再次读取的字符串是 : '{str_data}'
# 跳转到末尾并写入
f.seek(0, 2) # 移动到末尾
f.write("Appending using seek.\n") # 使用 seek 进行追加。\n
except FileNotFoundError:
print(f"Error: File '{file_path}' not found.") # 错误:未找到文件 '{file_path}'。
except IOError as e:
print(f"Error accessing file: {e}") # 访问文件错误: {e}

这将产生以下结果:

Read String is : 'Python is '
Current file position : 10
Again read String is : 'Python is '

os 和 pathlib 等模块提供了用于执行超出文件内容读写的文件系统任务的函数。

提供了与操作系统交互的平台无关的方式。

重命名文件:os.rename(current_name, new_name)

Section titled “重命名文件:os.rename(current_name, new_name)”
import os
# 首先创建一个虚拟文件
with open("test1.txt", "w") as f: f.write("dummy")
try:
os.rename("test1.txt", "test2.txt")
print("Renamed test1.txt to test2.txt") # 已将 test1.txt 重命名为 test2.txt
except OSError as e:
print(f"Error renaming file: {e}") # 重命名文件错误: {e}

删除文件:os.remove(file_name) 或 os.unlink(file_name)

Section titled “删除文件:os.remove(file_name) 或 os.unlink(file_name)”
try:
os.remove("test2.txt")
print("Removed test2.txt") # 已删除 test2.txt
except OSError as e:
print(f"Error removing file: {e}") # 删除文件错误: {e}

提供了文件路径的面向对象接口,通常使代码更具可读性。

from pathlib import Path
# 创建一个虚拟文件
dummy_file = Path("pathlib_test1.txt")
dummy_file.write_text("dummy content", encoding="utf-8")
new_file_path = Path("pathlib_test2.txt")
new_dir_path = Path("my_test_dir")
# 重命名
try:
dummy_file.rename(new_file_path)
print(f"Renamed {dummy_file} to {new_file_path}") # 已将 {dummy_file} 重命名为 {new_file_path}
except OSError as e:
print(f"Error renaming: {e}") # 重命名错误: {e}
# 删除
try:
new_file_path.unlink() # 对文件使用 unlink()
print(f"Removed {new_file_path}") # 已删除 {new_file_path}
except OSError as e:
print(f"Error removing: {e}") # 删除错误: {e}
# 创建目录
try:
new_dir_path.mkdir(exist_ok=True) # exist_ok=True 避免目录已存在时出错
print(f"Created directory {new_dir_path}") # 已创建目录 {new_dir_path}
except OSError as e:
print(f"Error creating directory: {e}") # 创建目录错误: {e}
# 获取当前目录
print(f"Current directory: {Path.cwd()}") # 当前目录: {Path.cwd()}
# 移除目录(必须为空)
try:
new_dir_path.rmdir() # 对目录使用 rmdir()
print(f"Removed directory {new_dir_path}") # 已移除目录 {new_dir_path}
except OSError as e:
print(f"Error removing directory (may not be empty): {e}") # 移除目录错误(可能非空): {e}

os 和 pathlib 都提供了管理目录的函数。

os.mkdir(path) 或 Path(path).mkdir()

os.chdir(path)(更改进程的当前工作目录)

os.getcwd() 或 Path.cwd()

os.rmdir(path) 或 Path(path).rmdir()(目录必须为空)

要移除包含内容的目录,请使用 shutil.rmtree(path)(请谨慎使用!)。

  • 内置 open():用于读写文件内容(与 with 一起使用)。
  • os 模块:传统的、基于函数的方法,用于操作系统交互(路径、进程)。os.path 子模块用于路径操作。
  • pathlib 模块:现代的、面向对象的方法,用于路径操作和基本文件操作。通常更受青睐。
  • shutil 模块:用于更高级的文件操作(复制、移动、移除目录树)。