Python 入门学习笔记
一:简介
Python 是一种高级的、解释型、动态类型并支持面向对象编程的语言。它具有简洁易读的语法,常使用英文关键字而非繁琐的符号(例如用 and
代替 &&
),从而降低了学习门槛。Python 最初由 Guido van Rossum 在 1989 年末设计,并于 1991 年发布了第一个版本。Python 拥有丰富的标准库和第三方库,在 web 开发、数据分析、人工智能等领域被广泛应用。值得注意的是,Python 2.x 系列已于 2010 年确定 2.7 为最后一个版本(目前已停止维护),学习时应使用 Python 3.x。
- 提示:学习时建议使用 Python 官方文档和可靠教程,保持持续动手练习。
- 交互模式:可以在终端输入
python3
进入交互式解释器,快速测试代码。 - 命名规范:遵循 PEP8 规范,变量和函数名采用小写蛇形(
snake_case
),类名采用首字母大写的驼峰式(CamelCase
)。常量名用全大写加下划线分隔(例如MAX_SIZE
)。 - 调试建议:在调试代码时,可插入
print()
打印变量,或使用 IDE/调试器单步跟踪。注释和文档字符串(docstring)有助于提高代码可读性并方便调试。
二:Python 基础语法
Python 代码由一系列语句构成,每个语句通常以换行结束。下面介绍一些基础概念:
字面量(Literal):字面量是源代码中直接写出的固定值。Python 支持多种字面量类型,例如整数、浮点数、复数、字符串、布尔值(
True
/False
)以及特殊值None
。例如:x = 42 # 整数字面量 y = 3.14 # 浮点数字面量 z = 1+2j # 复数字面量 s = "Hello" # 字符串字面量 flag = True # 布尔字面量 n = None # None特殊字面量,表示空值
注释:使用
#
表示单行注释,注释内容从#
开始直到行尾,Python 解释器会忽略它。例如:# 这是单行注释 x = 10 # 这是代码后的注释
Python 没有专门的多行注释符号,但可以用三重引号(
'''
或"""
)包围一段文字充当多行注释(严格来说,它是字符串字面量,但如果没有赋值就会被忽略)。
提示:编写函数或类时,建议使用文档字符串来说明功能,例如:def add(a, b): """返回两个数的和""" return a + b
根据约定,公有函数、类和模块都应包含三重引号的文档字符串。
数据类型转换:Python 提供内置函数将数据从一种类型强制转换为另一种类型,例如
int()
,float()
,str()
,bool()
等。例如:num_str = "123" num = int(num_str) # 将字符串转换为整数,num = 123 pi = str(3.14) # 将浮点数转换为字符串,pi = "3.14" b = bool(0) # 将数字转换为布尔,0 会被转换为 False,除了0和None以外其他的都是True
常见用法还包括
list()
,tuple()
,set()
,dict()
函数进行数据类型转换。标识符:变量名、函数名和类名等称为**标识符。标识符由字母、数字和下划线**组成,不能以数字开头,且区分大小写。例如
my_var
、_temp2
是合法标识符。标识符不能与 Python 的关键字同名(如if
,for
,def
等)。
提示:避免使用单字符l
,O
,I
等作为变量名,因为在某些字体下与数字1
,0
不易区分。运算符:Python 支持多种运算符,包括:
- 算术运算符:
+
(加),-
(减),*
(乘),/
(除,结果为浮点数),//
(整除),%
(取余),**
(幂运算)。 - 赋值运算符:
=
及组合形式如+=
,-=
,*=
等。 - 比较运算符:
==
,!=
,>
,<
,>=
,<=
。 - 逻辑运算符:
and
,or
,not
(注意 Python 中逻辑运算符是**关键字而非符号**)。 - 成员运算符:
in
,not in
(检查元素是否在容器中)。 - 身份运算符:
is
,is not
(判断对象标识是否相同)。
例如:
a = 10 b = 3 print(a + b, a ** b, a > b) # 输出:13 1000 True print("py" + "thon") # 字符串拼接,输出:python print(3 * "ha") # 字符串重复,输出:hahaha
提示:在 Python 3 中,
/
始终返回浮点数,若要整除请使用//
。逻辑表达式优先级可用括号明确。- 算术运算符:
字符串:字符串可以用单引号
''
、双引号""
或三引号''' '''
/""" """
定义(后者可表示多行字符串)。例如:str1 = 'Hello' str2 = "Python" str3 = '''多行 字符串'''
字符串可以用
+
连接,用*
重复。Python 3.6+ 引入了格式化字符串字面量(f-string),在字符串前加f
(或F
)并在{}
内嵌入表达式。例如:name = "Alice" age = 30 print(f"{name} 的年龄是 {age}") # 输出:Alice 的年龄是 30 print("{0} 的年龄是 {1}".format(name, age))
以上两种方式都可以格式化输出。旧式的
%
格式化也仍然可用,但更推荐使用str.format()
或 f-string。数据输入:使用
input(prompt)
从标准输入读取一行文本,返回**一个字符串**。例如:user = input("请输入用户名:") age_str = input("请输入年龄:") age = int(age_str) # 将输入的年龄字符串转换为整数
注意
input()
返回类型为字符串,需要根据需要进行类型转换。调试时可先打印输入值以检查正确性。
三:判断语句(if)
Python 使用缩进来划分代码块,判断语句格式为:
if 条件:
语句块
elif 另一个条件:
语句块
else:
语句块
条件表达式结果为布尔值 (True
或 False
)。例如:
x = 5
if x > 0:
print("正数")
elif x == 0:
print("零")
else:
print("负数")
在判断中,可以使用比较运算符和逻辑运算符组合复合条件。Python 中**非零数、非空字符串/列表**等被视为真(True
),而 0
、""
、[]
、None
等视为假(False
)。
注意:if
、elif
、else
后面**必须加冒号 :
,且对应的代码块需缩进(通常 4 个空格)**。缩进错误会导致 IndentationError
。建议使用编辑器自动缩进或在设置中启用可视化缩进指南。pycharm中可以使用快捷键
Ctrl + Alt + L
示例:
score = int(input("请输入成绩:")) if score >= 90: print("优秀") elif score >= 60: print("及格") else: print("不及格")
四:循环语句
Python 支持 while
循环和 for
循环:
while 循环:按照条件判断来重复执行代码块。例如:
n = 0 while n < 5: print(n) n += 1
如果循环条件始终为真,则会无限循环,需要注意保证循环变量能够改变以终止循环。可以使用
break
跳出循环,continue
跳过本次continue下面的语句直接执行下一次。for 循环:用于遍历序列或可迭代对象。常见用法是
range
函数生成数值序列:for i in range(5): # 生成 0,1,2,3,4 print(i)
range(stop)
生成从 0 到stop-1
的整数序列;range(start, stop)
生成从start
到stop-1
;range(start, stop, step)
可指定步长。需要注意的是,range
返回一个不可变的序列对象,可以通过list(range(...))
转为列表查看具体数字。也可以遍历列表、字符串等序列:
for ch in "Python": print(ch) for item in [1, 2, 3]: print(item)
for
循环也支持可选的else
分支,当循环正常完成(无break
)时会执行else
后的代码。
提示:尽量避免使用复杂的嵌套循环或不必要的 while True
无限循环。调试循环时,可在循环体中打印循环变量检查运行情况。
五:函数(Function)
函数通过 def
关键字定义,用于封装可复用的代码。基本形式:
def 函数名(参数列表):
"""函数文档字符串,可选,用于说明功能"""
函数体
return 返回值 # 可选
示例:
def add(a, b):
"""返回两个数的和"""
return a + b
result = add(3, 5) # 调用函数,result = 8
print(add) # 打印函数对象信息
函数在被调用时执行其中的语句,并可通过 return
返回结果。若没有显式 return
,函数执行完毕后返回 None
。
参数与调用:调用函数时可以使用位置参数或**关键字参数**,例如 add(2, 3)
或 add(a=2, b=3)
。Python 函数支持以下几种参数形式:
- 位置参数:按顺序传递。
- 关键字参数:
func(x=..., y=...)
指定参数名传递。 - 默认参数:
def func(a, b=10)
,若调用时未提供b
,则使用默认值 10。 - 可变参数:
*args
表示**接收多个位置参数为元组,**kwargs
表示接收多个关键字参数为字典。一个*
表示接受多余的没有使用关键字传递的参数,保存为元组类型**,两个**
号表示接受多余的传递的关键字参数,按照字典进行存储.
示例:
def greet(name, msg="你好"):
print(f"{msg},{name}!")
greet("李雷") # 使用默认消息
greet("韩梅梅", msg="欢迎")
文档字符串:如前所述,推荐在函数内部以三重引号写文档字符串,第一行简要说明功能,其后可详述参数和返回值。可以使用 help(func)
或 print(func.__doc__)
查看文档字符串。使用help(function)
或者function.__doc__
都可以.一个是python内置的函数,一个是类的魔法函数.
作用域:函数内部定义的变量为局部变量,只在函数内部有效;函数外部的变量可在函数中通过参数或使用 global
声明访问。避免不恰当地使用全局变量,以免引起命名冲突。
六:数据容器
1. 列表(list
)
列表是最常用的可变序列类型,支持动态增删查改。以下方法在日常开发中非常常见。
# 假设有一个初始列表
lst = [3, 1, 4, 1, 5]
print("初始列表: ", lst) # [3, 1, 4, 1, 5]
1.1 append(x)
在列表末尾添加一个元素
x
(原地修改)。
lst.append(9)
print("append(9) 之后: ", lst) # [3, 1, 4, 1, 5, 9]
1.2 extend(iterable)
将可迭代对象
iterable
中的所有元素依次添加到列表末尾(原地修改)。
lst.extend([2, 6, 5])
print("extend([2,6,5]) 之后: ", lst) # [3, 1, 4, 1, 5, 9, 2, 6, 5]
1.3 insert(i, x)
在索引
i
处插入元素x
,之后原来位于i
及之后的元素依次后移(原地修改)。
lst.insert(2, 8)
# 在索引 2 处插入 8,原 [3,1,4,...] 中索引2对应 4,插入后 4 向后移
print("insert(2,8) 之后: ", lst) # [3, 1, 8, 4, 1, 5, 9, 2, 6, 5]
1.4 remove(x)
删除列表中第一个值为
x
的元素,若不存在则抛出ValueError
(原地修改)。
lst.remove(1)
# 列表中第一个元素 1 会被移除
print("remove(1) 之后: ", lst) # [3, 8, 4, 1, 5, 9, 2, 6, 5]
1.5 pop([i])
删除并返回索引
i
处的元素(原地修改)。若不传入i
,则默认删除并返回最后一个元素;若索引越界抛出IndexError
。
val_last = lst.pop()
print("pop() 返回: ", val_last) # 5
print("pop() 之后: ", lst) # [3, 8, 4, 1, 5, 9, 2, 6]
val_idx3 = lst.pop(3)
print("pop(3) 返回: ", val_idx3) # 索引 3 处元素是 1
print("pop(3) 之后: ", lst) # [3, 8, 4, 5, 9, 2, 6]
1.6 clear()
清空列表中的所有元素(原地修改),变成空列表。
tmp = lst.copy()
tmp.clear()
print("clear() 之后: ", tmp) # []
1.7 index(x[, start[, end]])
返回列表中第一个值为
x
的元素索引。从start
开始(包含),到end
结束(不包含)。若找不到会抛出ValueError
。
lst2 = [10, 20, 30, 20, 40]
idx1 = lst2.index(20) # 第一个 20 的索引
print("lst2.index(20):", idx1) # 1
# 可以指定查找范围
idx2 = lst2.index(20, 2, 5) # 从索引2到索引4(不含5)查找 20
print("lst2.index(20, 2, 5):", idx2) # 3
1.8 count(x)
返回元素
x
在列表中出现的次数(不修改列表)。
cnt = lst2.count(20)
print("lst2.count(20):", cnt) # 2
1.9 sort(key=None, reverse=False)
对列表进行排序(原地修改)。
key
:用于指定排序依据的函数,如key=lambda x: x['age']
。reverse=True
则降序,否则升序(默认)。
lst3 = [5, 2, 9, 1, 5, 6]
lst3.sort()
print("lst3.sort() 之后升序:", lst3) # [1, 2, 5, 5, 6, 9]
lst3.sort(reverse=True)
print("lst3.sort(reverse=True) 之后降序:", lst3) # [9, 6, 5, 5, 2, 1]
# 自定义 key,例如按绝对值排序
lst4 = [-3, 1, -2, 5, -1]
lst4.sort(key=lambda x: abs(x))
print("按绝对值排序:", lst4) # [1, -1, -2, -3, 5]
1.10 reverse()
将列表中元素反转(原地修改,不同于
lst3[::-1]
返回一个新列表)。
lst5 = [1, 2, 3, 4]
lst5.reverse()
print("lst5.reverse():", lst5) # [4, 3, 2, 1]
1.11 copy()
返回列表的浅拷贝(相当于
lst[:]
)。若列表中包含可变对象,仍然是引用相同的可变对象。
lst6 = [[1, 2], [3, 4]]
lst6_copy = lst6.copy()
lst6_copy[0][0] = 100
print("lst6:", lst6) # [[100, 2], [3, 4]] —— 注意,浅拷贝依然修改了原来的子列表
print("lst6_copy:", lst6_copy) # [[100, 2], [3, 4]]
2. 元组(tuple
)
元组是有序、不可变的序列。由于不可变,方法相对较少,仅保留查询类操作。
tup = (10, 20, 30, 20, 40)
print("初始元组: ", tup)
2.1 count(x)
返回元素
x
在元组中出现的次数。
cnt = tup.count(20)
print("tup.count(20):", cnt) # 2
2.2 index(x[, start[, end]])
返回元组中第一个值为
x
的元素索引,可指定起止位置,找不到抛出ValueError
。
idx = tup.index(20) # 第一个 20 出现的位置
print("tup.index(20):", idx) # 1
# 指定范围查找
idx2 = tup.index(20, 2, 5)
print("tup.index(20, 2, 5):", idx2) # 3
注意:由于元组不可变,没有
append/pop/remove
等修改方法。
3. 字典(dict
)
字典是以“键-值”对(key-value pair)存储的无序容器,键必须是不可变类型(如字符串、数字、元组等)。以下方法在开发中经常用到。
d = {'name': 'Alice', 'age': 30, 'city': 'Beijing'}
print("初始字典: ", d)
3.1 get(key[, default])
返回键
key
对应的值。如果key
不存在,则返回default
(若未提供default
则返回None
),不会抛错。
print("d.get('name'):", d.get('name')) # 'Alice'
print("d.get('salary'):", d.get('salary')) # None
print("d.get('salary', 0):", d.get('salary', 0)) # 0
3.2 keys()
返回一个可迭代的视图(
dict_keys
)对象,其中包含字典的所有键。可以用list(d.keys())
转为列表。
print("d.keys():", d.keys()) # dict_keys(['name', 'age', 'city'])
print("转换为 list:", list(d.keys())) # ['name', 'age', 'city']
3.3 values()
返回一个可迭代的视图(
dict_values
)对象,其中包含字典的所有值。
print("d.values():", d.values()) # dict_values(['Alice', 30, 'Beijing'])
print("转换为 list:", list(d.values())) # ['Alice', 30, 'Beijing']
3.4 items()
返回一个可迭代的视图(
dict_items
)对象,其中包含字典的所有(key, value)
对。可用于解包、遍历等。
print("d.items():", d.items())
# dict_items([('name', 'Alice'), ('age', 30), ('city', 'Beijing')])
# 遍历示例
for k, v in d.items():
print(f"{k} -> {v}")
# 输出:
# name -> Alice
# age -> 30
# city -> Beijing
3.5 update([other])
用字典
other
(或可迭代的一系列(key,value)
对)更新当前字典:如果键存在则覆盖其值;不存在则新增。返回None
(原地修改)。
d2 = {'age': 31, 'salary': 100000}
d.update(d2)
print("d.update({'age':31,'salary':100000}) 之后:", d)
# {'name': 'Alice', 'age': 31, 'city': 'Beijing', 'salary': 100000}
# 也可以传入可迭代对象
d.update([('city', 'Shanghai'), ('dept', 'IT')])
print("再 update 一次:", d)
# {'name': 'Alice', 'age': 31, 'city': 'Shanghai', 'salary': 100000, 'dept': 'IT'}
3.6 pop(key[, default])
删除并返回键
key
对应的值。如果key
不存在且未给出default
,则抛出KeyError
;若提供default
,则返回default
。
age = d.pop('age')
print("pop('age') 返回:", age) # 31
print("pop 之后的 d:", d) # {'name':'Alice','city':'Shanghai','salary':100000,'dept':'IT'}
# key 不存在却提供 default,不会抛错
val = d.pop('不存在的键', 'N/A')
print("pop('不存在的键','N/A') 返回:", val) # 'N/A'
3.7 popitem()
随机删除并返回字典中的一对
(key, value)
。在 Python 3.7+ 中,popitem()
默认删除最后插入的那一对(相当于“栈”的行为)。如果字典为空则抛出KeyError
。
pair = d.popitem()
print("popitem() 返回:", pair)
print("popitem 之后的 d:", d)
3.8 setdefault(key[, default])
如果
key
存在于字典中,返回其对应的值;否则插入key: default
,并返回default
。default
默认为None
。
d.setdefault('dept', 'HR')
print("调用 setdefault('dept','HR'):", d['dept']) # 已经存在,不会改动,仍为 'IT'
# setdefault 插入一个新的键
val = d.setdefault('region', 'North')
print("setdefault('region','North') 返回:", val) # 'North'
print("之后的 d:", d)
# {'name': 'Alice', 'city': 'Shanghai', 'salary': 100000, 'dept': 'IT', 'region': 'North'}
3.9 clear()
清空字典,变成空字典
{}
(原地修改)。
tmp = d.copy()
tmp.clear()
print("clear() 之后:", tmp) # {}
3.10 copy()
返回字典的浅拷贝。拷贝之后,修改拷贝或原字典不会影响对方,但若值是可变对象,仍然引用同一对象。
d3 = {'a': [1, 2], 'b': [3, 4]}
d3_copy = d3.copy()
d3_copy['a'][0] = 999
print("d3:", d3) # {'a': [999, 2], 'b': [3, 4]}
print("d3_copy:", d3_copy) # {'a': [999, 2], 'b': [3, 4]}
4. 集合(set
)与 冰冻集合(frozenset
)
集合是无序、不重复的元素集合,常用于去重、数学集合运算等。frozenset
是不可变版本,常用于做字典键等。
s = {1, 2, 3}
print("初始集合 s:", s)
4.1 add(x)
将元素
x
添加到集合中,若x
已存在则不做任何操作(原地修改)。
s.add(4)
print("add(4) 之后:", s) # {1, 2, 3, 4}
s.add(2) # 集合已有 2,不会发生变化
print("add(2) 之后:", s) # {1, 2, 3, 4}
4.2 update(iterable)
用可迭代对象中的元素更新集合(相当于多次调用
add
,原地修改)。
s.update([3, 5, 6])
print("update([3,5,6]) 之后:", s) # {1, 2, 3, 4, 5, 6}
4.3 remove(x)
从集合中移除元素
x
,若x
不存在则抛出KeyError
(原地修改)。
s.remove(6)
print("remove(6) 之后:", s) # {1, 2, 3, 4, 5}
# s.remove(10) # KeyError: 10
4.4 discard(x)
从集合中移除元素
x
,若x
不存在则不做任何操作(原地修改)。
s.discard(5)
print("discard(5) 之后:", s) # {1, 2, 3, 4}
s.discard(10) # 不存在也不会报错
print("discard(10) 之后:", s) # {1, 2, 3, 4}
4.5 pop()
随机移除并返回一个元素(原地修改)。如果集合为空则抛出
KeyError
。
注意:因为集合是无序的,pop()
返回的元素是随机的。
elem = s.pop()
print("pop() 返回:", elem)
print("pop() 之后:", s)
4.6 clear()
清空集合中的所有元素(原地修改),变成空集合
set()
。
tmp = s.copy()
tmp.clear()
print("clear() 之后:", tmp) # set()
4.7 并集、交集、差集、对称差集
关于两个集合
A
、B
的常见运算:
A.union(B)
或A | B
:并集,返回包含 A、B 中所有元素的新集合。A.intersection(B)
或A & B
:交集,返回同时在 A 和 B 中出现的元素的新集合。A.difference(B)
或A - B
:差集,返回在 A 中但不在 B 中的元素的新集合。A.symmetric_difference(B)
或A ^ B
:对称差集,返回在 A、B 中但不同时在二者中的元素的新集合。
A = {1, 2, 3, 4}
B = {3, 4, 5, 6}
print("A ∪ B =", A.union(B), " 等价于 ", A | B)
# {1,2,3,4,5,6}
print("A ∩ B =", A.intersection(B), " 等价于 ", A & B)
# {3,4}
print("A - B =", A.difference(B), " 等价于 ", A - B)
# {1,2}
print("A △ B =", A.symmetric_difference(B), " 等价于 ", A ^ B)
# {1,2,5,6}
4.8 子集与超集判断
A.issubset(B)
或A <= B
:判断 A 是否为 B 的子集。A.issuperset(B)
或A >= B
:判断 A 是否为 B 的超集。A < B
:真子集(A 是 B 子集且 A ≠ B)。A > B
:真超集。
print("{1,2} 是否为 {1,2,3} 的子集?", {1,2}.issubset({1,2,3})) # True
print("{1,2} < {1,2,3}?", {1,2} < {1,2,3}) # True
print("{1,2,3} 是否为 {1,2} 的超集?", {1,2,3}.issuperset({1,2})) # True
print("{1,2,3} > {1,2}?", {1,2,3} > {1,2}) # True
4.9 frozenset(iterable)
创建一个不可变(哈希化)的集合,适合做字典键或集合元素。其方法与
set
类似,但所有“就地修改”方法都不存在。
fs = frozenset([1, 2, 3, 2])
print("frozenset:", fs) # frozenset({1, 2, 3})
# fs.add(4) # AttributeError: 'frozenset' object has no attribute 'add'
6. 其他与容器相关的常见方法或技巧
在开发中,除了上面列举的容器方法外,还有一些通用技巧或函数常与容器一起使用,这里一并简要列出。
6.1 列表生成式(List Comprehension)
虽然不是“方法”,但列表生成式几乎是 Python 开发中最常用的构造列表的方式。通常用于对现有列表或可迭代对象进行快速转换/过滤。
# 生成 0~9 的平方列表
squares = [i * i for i in range(10)]
print("squares:", squares) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# 带条件的生成式,筛选偶数的平方
even_squares = [i * i for i in range(10) if i % 2 == 0]
print("even_squares:", even_squares) # [0, 4, 16, 36, 64]
6.2 生成器表达式(Generator Expression)
与列表生成式类似,但返回一个生成器对象,可逐个迭代生成值,节省内存。常用于对大数据流的“惰性”处理。
gen = (i * i for i in range(10))
print("gen:", gen) # <generator object ...>
print("取前两个值:", next(gen), next(gen)) # 0 1
# 可以用 for 循环遍历
for val in gen:
print(val, end=" ") # 接着输出 4,9,16,...
6.3 zip()
、enumerate()
、map()
、filter()
等
zip(*iterables)
:并行遍历多个可迭代对象,返回元组序列。enumerate(iterable, start=0)
:将可迭代对象元素“打包”为(index, value)
对,常用于同时需要索引和元素的场景。map(func, *iterables)
:将func
应用于每个元素,返回一个生成器(Python 3 中)。filter(func, iterable)
:筛选iterable
中使func(item)
返回True
的元素,返回生成器。
A = ['a', 'b', 'c']
B = [1, 2, 3]
# zip 示例
for x, y in zip(A, B):
print(x, y)
# a 1
# b 2
# c 3
# enumerate 示例
for idx, val in enumerate(['x', 'y', 'z'], start=1):
print(idx, val)
# 1 x
# 2 y
# 3 z
# map 示例:把字符串列表转为大写
words = ['hello', 'world']
upper_words = list(map(str.upper, words))
print("upper_words:", upper_words) # ['HELLO', 'WORLD']
# filter 示例:筛选偶数
nums = list(range(10))
evens = list(filter(lambda x: x % 2 == 0, nums))
print("evens:", evens) # [0, 2, 4, 6, 8]
6.4 解包(Unpacking)
对于序列或可迭代对象,可以使用“星号”进行拆包,把第一部分、最后一部分或中间部分单独提取出来。在处理函数参数、交换变量、拆分列表时非常方便。
# 交换变量
a, b = 1, 2
a, b = b, a
print("交换后 a, b:", a, b) # 2 1
# 序列解包
numbers = [1, 2, 3, 4, 5]
first, *middle, last = numbers
print("first:", first) # 1
print("middle:", middle) # [2, 3, 4]
print("last:", last) # 5
# 函数参数解包
def func(x, y, z):
print("x:", x, "y:", y, "z:", z)
args = (10, 20, 30)
func(*args) # 相当于 func(10,20,30)
总结
以上内容涵盖了 Python 常用内置容器(list
、tuple
、dict
、set
)及 collections
模块常见的高级容器(deque
、defaultdict
、OrderedDict
、Counter
、namedtuple
)的核心方法,并通过示例演示了它们的典型用法。
- 列表 (
list
):动态增删查改涉及append
、extend
、insert
、remove
、pop
、clear
、index
、count
、sort
、reverse
、copy
等。 - 元组 (
tuple
):由于不可变,只保留查询类方法count
、index
。 - 字典 (
dict
):常见get
、keys
、values
、items
、update
、pop
、popitem
、setdefault
、clear
、copy
。 - 集合 (
set
):常见add
、update
、remove
、discard
、pop
、clear
、集合运算 (union
/intersection
/difference
/symmetric_difference
)、子集/超集判断。 frozenset
:不可变集合,仅支持读取和集合运算,不支持增删。- 其他常见函数/技巧:
zip
、enumerate
、map
、filter
,以及列表/生成器表达式、解包等,虽非“容器方法”,但在开发中与容器操作常结合使用。
- 提示:选用合适的数据结构。例如查找时列表复杂度较高,可以使用字典或集合。操作前可先打印或调试以检查数据结构正确性。
掌握并灵活运用上述方法,能大幅提升日常 Python 开发的效率与可读性。
七:函数进阶
在熟悉基本函数定义后,还可以掌握以下高级特性:
返回多个值:Python 中一个函数可以通过逗号返回多个值,实质上是返回一个元组。例如:
def get_point(): return 10, 20 x, y = get_point() print(x, y) # 10 20
参数传递方式:详述参数形式:
- 默认值参数:
def func(a, b=10)
; - 可变参数
*args
:允许传入任意数量的位置参数,函数内部以元组形式访问; - 关键字可变参数
**kwargs
:允许传入任意数量的关键字参数,函数内部以字典形式访问; - 关键字-only 参数:在
*
之后定义的参数只能通过关键字传入(Python 3)。
示例:
def demo(a, b=2, *args, **kwargs): print(a, b, args, kwargs) demo(1, 3, 4, 5, x=9, y=8) # a=1, b=3, args=(4,5), kwargs={'x':9,'y':8}
- 默认值参数:
匿名函数(Lambda):使用
lambda
定义简单函数,通常用于短小函数或作为参数传递。语法:lambda 参数: 表达式
。例如:f = lambda x, y: x + y print(f(2, 3)) # 5
lambda 函数只能写单个表达式,无法包含复杂语句。
函数作为参数:Python 函数是对象,可以作为其他函数的参数或返回值。例如:
def apply(func, arg): return func(arg) def square(x): return x * x print(apply(square, 5)) # 25 print(apply(lambda z: z+1, 7)) # 8
常见应用有内置函数
map(func, iterable)
、filter(func, iterable)
、sorted(iterable, key=func)
等,都使用函数作为参数。作用域与闭包:函数内部定义的变量默认是局部的,可以使用
global
声明访问全局变量。闭包是一种高级特性(函数返回另一个函数且后者使用了前者的局部变量),对初学者可稍后深入。
提示:为提高可读性,函数体内部的代码缩进通常为 4 个空格。避免使用过长或过多的参数(超过 3~4 个就考虑用字典传参)。尽量为复杂的函数写单元测试或使用 assert
进行简单调试。
八:文件操作
Python 提供丰富的文件读写功能。常见流程是使用 open()
打开文件,然后读取或写入,最后关闭文件。示例:
# 打开并读取文件内容
with open("data.txt", "r", encoding="utf-8") as f:
content = f.read() # 读取整个文件
print(content)
# 遍历读取行
with open("data.txt", "r", encoding="utf-8") as f:
for line in f:
print(line.strip())
# 写入文件(会覆盖原内容)
with open("out.txt", "w", encoding="utf-8") as f:
f.write("Hello, world!\n")
f.write("第二行内容\n")
# 追加写入
with open("out.txt", "a", encoding="utf-8") as f:
f.write("追加的一行\n")
open(filename, mode, encoding)
:mode
参数可为'r'
(读)、'w'
(写,覆盖)、'a'
(追加)、'rb'/'wb'
(二进制读写)等。默认文本模式下使用 UTF-8 编码(Python 3)。- 使用
with open(...) as f:
结构可以自动管理文件关闭,即使发生异常也会自动关闭文件。完成后无需手动调用f.close()
。 - 读操作方法:
f.read()
读取全部内容,f.readline()
读取一行,f.readlines()
读取所有行返回列表。 - 写操作方法:
f.write(string)
写入字符串(需要显式换行符\n
)。
提示:文件操作时建议捕获异常(如文件不存在时会 FileNotFoundError
),并确保使用 with
管理上下文。对二进制文件(如图片、音频),应使用 'rb'
/'wb'
模式。不要忘了在写入文本时指定正确的编码以避免乱码。
九:异常、模块与包
异常处理:在程序运行过程中可能发生错误(如除零、文件未找到等)。可以用
try...except
结构捕获并处理异常。基本语法:try: 可能引发异常的代码 except 具体异常类型 as e: 异常处理代码 except (异常类型1, 异常类型2): 处理多种异常 else: 如果没有发生异常则执行 finally: 无论是否发生异常都会执行的代码(通常用于清理)
示例:
try: num = int(input("输入一个整数:")) result = 10 / num except ValueError: print("请输入有效的整数") except ZeroDivisionError: print("除数不能为 0") else: print("计算结果:", result) finally: print("程序结束")
若不捕获异常,程序会终止并打印错误信息。正确的异常处理使程序健壮且用户友好。注意:不要使用过于宽泛的
except:
,最好指定具体异常类型。模块:Python 模块(Module)是一个以
.py
为后缀的文件,用于定义函数、类和全局变量等。通过模块可以逻辑分块组织代码,提高复用性。使用import
关键字导入模块:# 假设当前目录下有 utils.py 文件 import utils # 导入整个模块 from utils import foo # 从模块导入函数/变量 print(utils.foo(5))
模块可以重命名:
import utils as u
。避免循环导入和命名冲突。自定义模块:直接在项目文件夹中创建
.py
文件,或将其放在 Python 的搜索路径内。可以使用if __name__ == "__main__":
语句块让模块既能导入也能作为脚本运行。包:包(Package)是具有层次结构的目录结构,用于组织模块。简单来说,包就是一个包含子模块(和子包)的文件夹,必须包含一个名为
__init__.py
的文件(可为空),用于标识该目录为包。示例目录结构:mypackage/ __init__.py module1.py subpkg/ __init__.py module2.py
使用时可以这样导入:
import mypackage.module1
或from mypackage.subpkg import module2
。包机制避免了模块命名冲突,提高了代码组织性。异常(扩展):可以使用
raise
自己触发异常,或者定义新的异常类(通常继承自Exception
)。示例:def sqrt(x): if x < 0: raise ValueError("参数必须是非负数") return x ** 0.5
当
x
为负时,函数会抛出ValueError
异常。调用方可捕获并处理。
提示:捕获异常时,应尽量缩小 try
块的范围,只包含可能发生错误的代码。使用 print()
或日志记录模块 logging
记录错误信息有助于调试。模块导入时,可使用虚拟环境和 pip
管理依赖。
十:Python 面向对象编程学习笔记
1. 类的定义与实例化
在 Python 中,使用 class
语句定义类,类体中可以包含类变量和方法。类的构造函数是 __init__()
方法,它会在创建实例时自动调用。举例来说:定义一个 Person
类,并创建其实例(instance
):
class Person:
"""表示一个人"""
species = "Homo sapiens" # 类变量,所有实例共享
def __init__(self, name):
self.name = name # 实例变量,仅属于当前实例
# 实例化类
p = Person("Alice")
print(p.name) # 输出: Alice
print(Person.species) # 访问类变量,共享值
以上代码中,Person
类的实例通过调用 Person("Alice")
创建。实例化时会执行 __init__()
,其中 self.name = name
将参数 name
存到实例属性。species
是类变量,对所有实例共享。可以使用 实例.属性
或 类名.类变量
访问这些属性。
2. 成员变量与类变量的区别
Python 类的变量分为类变量和实例变量。类变量定义在类体内,属于类本身,所有实例共享同一个值;实例变量通常在 __init__
方法里通过 self.xxx
定义,每个实例独立拥有。示例:
class Example:
counter = 0 # 类变量
def __init__(self, value):
self.value = value # 实例变量
Example.counter += 1
# 创建实例
e1 = Example(10)
e2 = Example(20)
print(e1.value, e2.value) # 输出: 10 20,实例变量互不影响
print(Example.counter) # 输出: 2,类变量被所有实例共享:contentReference[oaicite:3]{index=3}
- 类变量:在类体中定义(如
counter
),通过ClassName.counter
或实例.counter
访问,所有实例共用一个值。 - 实例变量:通常在
__init__()
中用self.xxx
定义(如self.value
),仅作用于各自的实例,不同实例互不干扰。
3. 方法类型:实例方法、类方法、静态方法
Python 类中的方法根据参数和装饰器分为三种类型:
实例方法:第一个参数为
self
,代表实例自身。调用时只能通过实例调用,它可以访问实例属性和类属性。例如:class MyClass: def instance_method(self): print(f"Instance method called on {self}") obj = MyClass() obj.instance_method() # 调用实例方法,隐式传入 obj 作为 # self:contentReference[oaicite:6]{index=6}
类方法:使用
@classmethod
装饰,第一个参数为cls
,代表类本身。类方法可以访问类变量或修改类状态,但**不能访问实例属性**。调用时可以使用ClassName.method()
或instance.method()
(不推荐实例调用)。例如:class MyClass: count = 0 @classmethod def class_method(cls): print(f"类方法: 当前 count={cls.count}") MyClass.class_method() # 输出: 类方法: 当前 count=0:contentReference[oaicite:7]{index=7}
静态方法:使用
@staticmethod
装饰,不接收self
或cls
参数。静态方法类似普通函数,但属于类的命名空间。它不能访问实例属性或类属性,只是放在类里便于组织代码。调用方式同类方法。示例:class MyClass: @staticmethod def static_method(x, y): return x + y print(MyClass.static_method(2, 3)) # 输出: 5:contentReference[oaicite:8]{index=8}
简言之,实例方法绑定实例并自动传递实例;类方法绑定类并自动传递类;静态方法没有自动传参。
4. 封装与 @property
封装是将对象的属性和实现细节隐藏起来,只通过公开的方法与外界交互。在 Python 中,可以通过以下方式实现封装:
- 对属性(变量)加下划线前缀(如
_x
或__x
),表明这是受保护或私有的属性,外部不宜直接访问。 - 使用
@property
装饰器,将方法伪装成属性,提供对私有属性的读写控制。这样外部可以像访问属性一样调用方法,从而在赋值和取值时加入检查逻辑。示例:
class Account:
def __init__(self, balance):
self.__balance = balance # 私有属性
@property
def balance(self):
return self.__balance # 定义 getter
@balance.setter
def balance(self, amount):
if amount < 0:
raise ValueError("余额不能为负")
self.__balance = amount # 定义 setter
acct = Account(100)
print(acct.balance) # 通过属性访问 getter
acct.balance = 200 # 通过属性访问 setter
上例中,balance
方法被 @property
装饰后可通过 acct.balance
访问,外部无法直接修改私有变量 __balance
,从而实现了数据保护。
5. 继承、多重继承与 MRO
Python 通过继承(inheritance)实现类之间的代码复用。子类在定义时将父类放入括号中,例如:class B(A):
表示 B
继承 A
。Python 支持多重继承,例如 class C(A, B):
同时继承 A
和 B
。在多重继承的情况下,方法解析顺序(MRO, Method Resolution Order)决定了搜索方法和属性的顺序(就是决定使用那个变量那个方法,如果存在重复的话)。Python 3 使用 C3 线性化算法来确定 MRO,使得菱形继承(多个父类继承自同一祖先)时有一致的查找顺序。可以通过 ClassName.__mro__
查看类的继承顺序。示例:
class A:
def msg(self): print("来自 A")
class B(A):
def msg(self): print("来自 B")
class C(A):
def msg(self): print("来自 C")
class D(B, C): # 多重继承
pass
# 上述就是一个菱形继承
d = D()
d.msg() # 调用 B 的 msg,按照 D -> B -> C -> A 的 MRO 查找
print(D.__mro__) # 查看方法解析顺序
在上述例子中,D.msg()
会先调用 B
的实现,按照 MRO 依次为 D, B, C, A, object
。
应该比较懵逼吧,接下来就是详细的讲解一下MRO
的知识点:
5.2 Python 继承与 MRO 深度解析
一、继承基础概念
class Parent:
def show(self):
print("Parent method")
class Child(Parent):
def show(self):
print("Child method")
super().show() # 调用父类方法
c = Child()
c.show()
"""
输出:
Child method
Parent method
"""
- 单继承时方法解析简单明确
super()
用于显式调用父类方法
二、多继承带来的挑战
菱形继承问题(钻石问题)
class A:
def show(self):
print("A")
class B(A):
def show(self):
print("B")
super().show()
class C(A):
def show(self):
print("C")
super().show()
class D(B, C):
def show(self):
print("D")
super().show()
d = D()
d.show()
问题:方法调用路径存在歧义
期望结果:D → B → C → A(调用完成D的之后接下来到底该先调用谁的B?C?)
三、MRO 的演进历史
1. Python 2.2 之前:深度优先搜索(DFS)
class X: pass
class Y(X): pass
class Z(X, Y): pass # 旧式类会报错
- 经典类(不继承 object)使用 DFS
- 无法处理菱形继承问题
2. Python 2.2:新旧 MRO 混合
- 新式类(继承 object)引入
__mro__
属性 - 使用广度优先搜索(BFS)与 DFS 混合算法
3. Python 2.3+:C3 线性化算法
- 当前 Python 3 统一采用的算法
- 解决多继承的二义性问题
四、C3 算法原理
1. 算法核心规则
- 单调性:如果类 C 在 MRO 中出现在类 B 之前,那么 C 的所有子类也必须出现在 B 之前
- 局部优先:父类声明顺序决定优先级
2. 算法步骤
给定类 C 的继承列表 [B1, B2, …, BN]:
- 计算每个父类的 MRO
- 创建合并列表:C + 父类 MRO 的合并
- 检查头元素是否合法:
- 不在其他列表的尾部
- 满足单调性要求
3. 公式表示
L[C(B1...BN)] = C + merge(L[B1],..., L[BN], B1...BN)
其中 merge 操作:
- 取第一个列表的头元素
- 如果该元素不在其他列表的尾部,则加入结果
- 否则检查下一个列表的头元素
- 重复直到所有列表为空
五、MRO 实战分析
1. 查看 MRO 顺序
print(D.__mro__) # 或 D.mro()
# 输出:(<class '__main__.D'>, <class '__main__.B'>,
# <class '__main__.C'>, <class '__main__.A'>,
# <class 'object'>)
2. 复杂继承案例
class O: pass
class F(O): pass
class E(O): pass
class D(O): pass
class C(D,F): pass
class B(D,E): pass
class A(B,C): pass
print(A.mro())
"""
结果:
[<class '__main__.A'>,
<class '__main__.B'>,
<class '__main__.D'>,
<class '__main__.C'>,
<class '__main__.E'>,
<class '__main__.F'>,
<class '__main__.O'>,
<class 'object'>]
"""
六、MRO 冲突与检测
1. 合法继承结构
class X: pass
class Y: pass
class A(X, Y): pass # 合法
2. 非法继承结构
class X: pass
class Y(X): pass
class Z(X, Y): pass # 触发 TypeError
"""
TypeError: Cannot create a consistent method resolution
order (MRO) for bases X, Y
"""
七、super() 的工作原理
1. 动态查找机制
class A:
def method(self):
print("A")
class B(A):
def method(self):
print("B")
super().method()
class C(A):
def method(self):
print("C")
super().method()
class D(B, C):
def method(self):
print("D")
super().method()
d = D()
d.method()
"""
输出:
D
B
C
A
"""
2. super() 参数详解
class Base:
def method(self):
print("Base")
class Child(Base):
def method(self):
print("Child")
super(Child, self).method() # 显式指定
八、最佳实践与注意事项
- 避免复杂多重继承:优先使用组合模式
- 统一使用 super():保持 MRO 一致性
- 注意初始化顺序:
class Base:
def __init__(self):
print("Base init")
class Mixin:
def __init__(self):
print("Mixin init")
super().__init__()
class MyClass(Mixin, Base):
def __init__(self):
print("MyClass init")
super().__init__()
obj = MyClass()
"""
输出:
MyClass init
Mixin init
Base init
"""
通过理解 MRO 机制,开发者可以:
✅ 准确预测方法调用顺序
✅ 设计合理的类继承结构
✅ 避免多继承常见陷阱
✅ 编写可维护的面向对象代码
6. 方法重写与 super()
子类可以通过重写(override)父类的方法来改变或扩展其行为,即在子类中定义一个与父类同名的方法。如果子类想在重写的同时调用父类的原方法,可以使用 super()
函数。例如:
class Animal:
def eat(self):
print("Animal 正在吃")
class Cat(Animal):
def eat(self):
super().eat() # 调用父类的 eat()
print("Cat 吃老鼠") # 添加新的行为
c = Cat()
c.eat()
输出结果会先执行 Animal
的 eat()
,再执行 Cat
的额外行为。这样就利用 super()
在保留父类功能的基础上添加了子类特有的逻辑。
7. 多态与鸭子类型
多态(polymorphism)指的是允许不同类的实例以相同的接口调用,表现出不同的行为。在 Python 中,通过继承并重写方法可以实现多态。例如:
class Animal:
def speak(self):
print("动物发声")
class Dog(Animal):
def speak(self):
print("汪汪汪")
class Cat(Animal):
def speak(self):
print("喵喵喵")
def make_sound(obj: Animal):
obj.speak()
make_sound(Dog()) # 输出: 汪汪汪
make_sound(Cat()) # 输出: 喵喵喵
上述例子中,make_sound
函数接受 Animal
类型的对象,对不同子类实例调用同名方法,产生不同输出,实现了多态。
Python 中的鸭子类型(duck typing)则强调不关心对象的实际类型,只关心对象是否具有特定的方法或行为。即“如果它像鸭子、走起路来像鸭子、叫起来像鸭子,那就是鸭子”。例如,只要一个对象有 speak()
方法,就可以被当作具有多态性的对象使用,无需显式继承某个接口。
8. 魔术方法
魔术方法(special methods)也称双下划线方法,如 __init__
, __str__
等,它们由 Python 内部调用,用于定制类的行为。常见的魔术方法包括:
__init__(self, …)
:构造函数,用于初始化新实例。__str__(self)
:定义str(obj)
及print(obj)
时的用户可读输出;__repr__(self)
:定义调试和交互环境下的输出,目标是“正式的”字符串表示。Python 规定__str__
用于给用户看,__repr__
用于给开发者看。例:class Person: def __init__(self, name): self.name = name def __str__(self): return f"Person: {self.name}" def __repr__(self): return f"Person({self.name!r})" p = Person("Bob") print(p) # 使用 __str__ 输出: Person: Bob p # 在 REPL 中显示 __repr__: Person('Bob')
__len__(self)
:使len(obj)
返回对象长度。如果类表现得像序列或集合,通常定义该方法。__eq__(self, other)
/__lt__(self, other)
等比较方法:定义==
、<
等运算符的行为。__getitem__(self, key)
:使对象支持索引和切片,如obj[key]
调用该方法。
例如,自定义一个容器类实现这些魔术方法:
class MyList:
def __init__(self, data):
self._data = list(data)
def __len__(self):
return len(self._data) # 支持 len()
def __getitem__(self, index):
return self._data[index] # 支持索引操作
def __eq__(self, other):
return self._data == other._data # 支持 == 比较
def __str__(self):
return str(self._data)
def __repr__(self):
return f"MyList({self._data})"
总之,魔术方法赋予类自定义行为,例如让对象能使用内置函数 len()
、通过 ==
比较、通过索引访问等,使得自定义类能像内置类型一样使用。
9. 运算符重载
运算符重载实质上就是定义相应的魔术方法,比如 +
运算符调用 __add__()
方法。通过在类中实现这些方法,可以让实例支持使用标准运算符。示例:
class Vector2D:
def __init__(self, x, y):
self.x, self.y = x, y
def __add__(self, other):
# 重载加法运算符:返回新向量
return Vector2D(self.x + other.x, self.y + other.y)
def __repr__(self):
return f"Vector2D({self.x}, {self.y})"
v1 = Vector2D(1, 2)
v2 = Vector2D(3, 4)
print(v1 + v2) # 输出: Vector2D(4, 6)
在上述代码中,对象 v1 + v2
实际上调用了 v1.__add__(v2)
,将两个向量的对应分量相加后返回新向量。类似地,可重载减法、乘法等(__sub__
、__mul__
等)以及其他运算符。这样使自定义类的实例能够自然地使用算术运算符。
10. 抽象类与接口(使用 abc
模块)
抽象类定义了一个接口规范,不能被实例化,只能被子类继承。它通常包含一个或多个抽象方法,这些方法没有实现,要求所有子类必须重写。Python 通过 abc
模块支持抽象基类(ABC)。例如:
from abc import ABC, abstractmethod
class Shape(ABC):
"""形状的抽象基类"""
@abstractmethod
def area(self):
pass
class Circle(Shape):
def __init__(self, r):
self.r = r
def area(self):
return 3.14 * self.r * self.r
# Shape() 不能实例化,否则会报错
c = Circle(5)
print(c.area())
在以上代码中,Shape
类继承自 ABC
并使用 @abstractmethod
装饰 area()
方法。这意味着 Shape
是抽象类,不能直接创建实例。 只有在子类中实现了所有抽象方法后,才能实例化子类。Python 中没有专门的接口关键字,但抽象类可以充当接口的角色。
11. 组合 vs 继承
在面向对象设计中,继承(is-a)和组合(has-a)是两种不同的复用方式。
- 继承:子类与父类之间是一种“是”的关系,如
Cat
是一种Animal
。继承适用于类别之间具有明确的层次关系、子类需要重用父类的大部分功能的场景。 - 组合:一个类包含另一个类的实例,建立“有”的关系,比如
Car
有一个Engine
。组合适用于两个类各自独立,一个类需要在实现时使用另一个类的场景。
例如:
# 继承示例
class Animal:
def walk(self): print("动物在走")
class Dog(Animal):
pass
dog = Dog()
dog.walk() # 输出: 动物在走
# 组合示例
class Engine:
def start(self): print("发动机启动")
class Car:
def __init__(self):
self.engine = Engine() # 组合:Car 拥有一个 Engine
def drive(self):
self.engine.start()
print("汽车驾驶中")
car = Car()
car.drive()
设计建议通常多用组合,少用继承。即只有在类之间确实存在 “是-a” 关系且能增强代码可复用性时才使用继承;否则更倾向于通过组合来组合对象以保持灵活性。
12. 常见 OOP 设计建议与模式
面向对象设计中常用一些设计模式和建议来提高代码质量:
单例模式(Singleton):确保某个类只有一个实例,并提供全局访问点。在 Python 中可通过重写
__new__
来实现单例,确保多次创建返回同一个实例。示例代码:class Singleton: _instance = None def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = super().__new__(cls) return cls._instance a = Singleton() b = Singleton() print(a is b) # True,只有一个实例
工厂模式(Factory):提供一个用于创建对象的接口,根据输入参数决定实例化哪个类。适用于需要创建多种相关对象且需解耦客户端与具体类的场景。示例代码:
class BMW: def run(self): print("宝马奔跑中") class Audi: def run(self): print("奥迪奔驰中") class CarFactory: @staticmethod def make_car(model): if model == "BMW": return BMW() elif model == "Audi": return Audi() car = CarFactory.make_car("BMW") car.run() # 输出: 宝马奔跑中:contentReference[oaicite:41]{index=41}
策略模式(Strategy):定义一系列可互换算法,将它们分别封装在不同类中,使得算法可独立于使用它的客户端变化。客户端可以在运行时动态选择策略对象。示例结构:
class StrategyA: def execute(self): print("算法A") class StrategyB: def execute(self): print("算法B") class Context: def __init__(self, strategy): self.strategy = strategy def do_something(self): self.strategy.execute() context = Context(StrategyA()) context.do_something() # 输出: 算法A
设计建议:遵循面向对象设计原则,如“依赖抽象、单一职责、接口隔离”,以及优先使用组合而非继承。良好的模式能提高代码复用性、可维护性和可扩展性。
十一: print
函数
1. 基本语法
print()
是 Python 中最基础且最常用的函数之一,用于将对象输出到标准输出(通常是控制台)。它支持丰富的参数和格式化功能。
1.1 最简单的形式
print("Hello World") # 输出: Hello World
1.2 打印多个对象
name = "Alice"
age = 25
print("Name:", name, "Age:", age) # 输出: Name: Alice Age: 25
2. 参数详解
print()
函数有四个关键参数:
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
2.1 sep
(分隔符)
- 默认使用空格分隔多个对象
print("2023", "10", "01", sep="-") # 输出: 2023-10-01
print("a", "b", "c", sep=" → ") # 输出: a → b → c
2.2 end
(结束符)
- 默认添加换行符
\n
print("Hello", end=" ")
print("World") # 输出: Hello World(同一行)
2.3 file
(输出目标)
- 默认输出到控制台,可重定向到文件
with open("output.txt", "w") as f:
print("Save to file", file=f) # 内容写入 output.txt
2.4 flush
(强制刷新)
- 默认 False,设置为 True 会立即刷新缓冲区
import time
print("Loading", end="", flush=True)
for _ in range(3):
time.sleep(1)
print(".", end="", flush=True) # 实时显示进度
# 输出: Loading...(每秒显示一个点)
3. 字符串格式化
3.1 旧式格式化 (%
)
price = 19.99
print("Price: $%.2f" % price) # 输出: Price: $19.99
3.2 str.format()
print("{0} + {1} = {2}".format(3, 5, 3+5)) # 输出: 3 + 5 = 8
print("Name: {name}, Age: {age}".format(name="Bob", age=30))
3.3 f-strings (Python 3.6+)
quantity = 5
item = "apples"
print(f"I have {quantity} {item}") # 输出: I have 5 apples
print(f"Result: {2**10}") # 输出: Result: 1024
print(f"Hex: {255:#x}") # 输出: Hex: 0xff
4. 输出重定向
4.1 临时重定向
import sys
with open('log.txt', 'w') as f:
sys.stdout = f # 重定向标准输出
print("This goes to log.txt")
sys.stdout = sys.__stdout__ # 恢复默认
4.2 同时输出到控制台和文件
from contextlib import redirect_stdout
with open('output.txt', 'w') as f, redirect_stdout(f):
print("This writes to file")
print("Also visible on console", file=sys.stdout)
5. 高级用法
5.1 打印特殊字符
print("Line1\nLine2") # 换行符
print("Tab\tSeparated") # 制表符
print("Backslash: \\") # 转义反斜杠
5.2 打印原始字符串
print(r"C:\Users\Name") # 输出: C:\Users\Name(不转义)
5.3 打印对象信息
class Dog:
def __init__(self, name):
self.name = name
buddy = Dog("Buddy")
print(buddy) # 默认输出: <__main__.Dog object at 0x...>
5.4 彩色输出
print("\033[31mRed Text\033[0m") # 输出红色文字
print("\033[44mBlue Background\033[0m")
6. 注意事项
6.1 类型自动转换
print(10 + 20) # 输出: 30(数字计算)
print("10" + "20") # 输出: 1020(字符串拼接)
6.2 处理非ASCII字符
print("中文") # Python 3 默认支持UTF-8
print("😊 Unicode Emoji")
6.3 性能优化
- 避免在循环中频繁打印:
# 低效方式
for i in range(10000):
print(i)
# 高效方式
output = '\n'.join(str(i) for i in range(10000))
print(output)
提示:在 Jupyter Notebook 中,
print()
可能不会立即显示所有输出,可使用flush=True
强制刷新缓冲区。