1. 等待用户输入


1
2
s = input("请输入:");  # 请输入:123
print ("你输入的内容是: ", s) # 你输入的内容是:123

程序结尾等待按回车退出

1
input("\n按回车键退出程序...")

例如:

1
2
print("程序运行完毕")
input("\n按回车键退出...")

2. 同一行显示多条语句


Python 可以在同一行中使用多条语句,语句之间使用分号 ; 分割,以下是一个简单的实例:

1
2
a = 1; b = 2; c = a + b
print(c) # 输出:3

3. 输出


print 默认输出是换行的,如果要实现不换行需要在变量末尾加上 end="":

1
2
3
4
5
6
7
8
9
10
x="a"
y="b"
# 换行输出
print( x )
print( y )
print('---------')
# 不换行输出
print( x, end=" " )
print( y, end=" " )
print()

print 不换行

4. f-string


  • f-string(格式化字符串字面量)是 Python 中最现代、最简洁且性能最佳的字符串格式化方法。
  • 可以非常简洁地格式化整数,包括补零、对齐、千位分隔等操作。

4.1 基础语法与使用

f-string 的基本用法是在字符串前添加小写字母 'f' 或大写字母 'F' ,并在字符串中使用花括号 {} 嵌入表达式:

1
2
3
4
5
6
7
8
9
10
# 基本用法
name = "张三"
age = 25
balance = 1500.75

# Python 3.6+
print(f"用户 {name},年龄 {age},账户余额 {balance} 元")

# Python 3.8+ 调试功能
print(f"用户 {name!r} 的余额为 {balance:.2f} 元")

输出

1
2
用户 张三,年龄 25,账户余额 1500.75 元
用户 '张三' 的余额为 1500.75 元

4.2 表达式嵌入

f-string 的一个强大特点是可以在花括号内直接执行表达式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 简单表达式
x = 10
y = 20
print(f"10 + 20 = {x + y}") # 输出:10 + 20 = 30

# 函数调用
def double(num):
return num * 2

print(f"5的两倍是 {double(5)}") # 输出:5的两倍是 10

# 条件表达式
is_rich = balance > 10000
status = "富有" if is_rich else "普通"
print(f"用户状态:{status}") # 输出:用户状态:普通

4.3 高级格式化选项

f-string 支持丰富的格式化选项,通过在花括号内使用冒号:后跟格式说明符实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 数值格式化
pi = 3.141592653589793
print(f"π的近似值为 {pi:.4f}") # 四位小数 → 3.1416

# 千位分隔符
revenue = 1234567.89
print(f"收入:{revenue:,.2f} 元") # 输出:收入:1,234,567.89 元

# 对齐与填充
# 左对齐,宽度10,填充空格
print(f"左对齐:{name:<10}")

# 右对齐,宽度10,填充空格
print(f"右对齐:{name:>`10}")

# 居中对齐,宽度10,填充*
print(f"居中填充:{name:*^10}")

# 补零
print(f"序号:{age:0>3d}") # 输出:序号:025

4.4 Python 3.8+ 的调试增强

Python 3.8 引入了 = 操作符,用于调试目的:

1
2
3
4
5
6
7
8
9
10
11
# 调试功能
def calculate_statistics(data):
total = sum(data)
average = total / len(data)
print(f"原始数据: {data=}")
print(f"总和: {total=}")
print(f"平均值: {average=:.2f}")
return average

numbers = [1, 2, 3, 4, 5]
result = calculate_statistics(numbers)

输出

1
2
3
原始数据: data=[1, 2, 3, 4, 5]
总和: total=15
平均值: average=3.0

4.5 Python 3.12 的改进

Python 3.12 版本对 f-string 进行了多项增强,使其更加灵活和强大:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 支持多行表达式
from datetime import datetime
now = datetime.now()
print(f"""
当前时间:
年:{now.year}
月:{now.month}
日:{now.day}
时:{now.hour}
分:{now.minute}
秒:{now.second}
""")

# 支持注释
# 计算并显示用户年龄
age = 25
print(f"用户年龄:{age} # 用户已成年")

# 支持反斜杠转义
path = "data\\user\\"
print(f"文件路径:{path} # 注意反斜杠转义")

# 支持嵌套相同引号
quote = "他说:'你好'"
print(f"带引号的字符串:{quote}")

5. format 方法📚

  • 兼容旧版的灵活格式化
  • str.format() 方法是 Python 3.6 之前的主流格式化方式,它提供强大的灵活性,支持位置参数、关键字参数和格式化选项

5.1 参数定位方式

format方法支持三种参数定位方式:

1
2
3
4
5
6
7
8
9
10
11
# 位置参数(按顺序)
print("用户:{},年龄:{}".format(name, age)) # 输出:用户:张三,年龄:25

# 显式位置索引(可重复使用)
print("年龄:{1},用户:{0}".format(name, age)) # 输出:年龄:25,用户:张三

# 关键字参数(提高可读性)
print("用户:{user},年龄:{years}".format(user=name, years=age))

# 混合使用(位置参数必须在关键字参数之前)
print("用户:{0},年龄:{years}".format(name, years=age))

5.2 格式说明符语法

format 方法的格式说明符采用[[fill][align]][width][.precision]type结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 填充与对齐
# 左对齐,宽度10,填充空格
print("{:<10}".format(name)) # 输出:张三

# 右对齐,宽度10,填充空格
print("{:`>10}".format(name)) # 输出:张三

# 居中对齐,宽度10,填充*
print("{:*^10}".format(name)) # 输出:***张三***

# 填充字符与对齐
print("{:*^10}".format(name)) # 输出:***张三***

# 数值格式化
# 固定小数位数
print("π值:{:.4f}".format(pi)) # 四位小数 → 3.1416

# 千位分隔符
print("收入:{:,}".format(revenue)) # 输出:收入:1,234,567.89

# 科学计数法
print("小数:{:.2e}".format(0.000123456)) # 输出:小数:1.23e-04

# 进制转换
print("十进制:{0}, 八进制:{0:o}, 十六进制:{0:x}".format(255))
# 输出:十进制:255, 八进制:377, 十六进制:ff

5.3 动态参数处理

format 方法在处理动态参数方面具有优势:

1
2
3
4
5
6
7
8
9
10
11
12
# 从字典获取参数
user_info = {
"name": "李四",
"age": 30,
"email": "lisi@example.com"
}

print("用户:{name}, 年龄:{age}, 邮箱:{email}".format(**user_info))

# 从列表获取参数
players = ["王五", "赵六", "陈七"]
print("冠军:{0[0]}, 亚军:{0[1]}, 季军:{0[2]}".format(players))

5.4 复杂数据格式化

format 方法支持对复杂数据类型的格式化:

1
2
3
4
5
6
7
8
9
10
11
12
# 日期格式化
from datetime import datetime
now = datetime.now()
print("日期:{:%Y-%m-%d}".format(now)) # 输出:日期:2026-03-31

# 列表格式化
numbers = [1, 2, 3, 4, 5]
print("数字:{}".format(", ".join(map(str, numbers))))

# 字典格式化
data = {"温度": 25, "湿度": 65, "风速": 10}
print("天气:温度={温度}°C,湿度={湿度}%,风速={风速}km/h".format(**data))

6. f-string 与 format📚

  • f-string 与 format 方法的性能与场景对比
  • f-string 和 format 方法各有优劣,选择合适的格式化方式取决于具体应用场景

6.1 性能对比

根据基准测试,f-string 在大多数情况下性能更优:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 简单格式化
import timeit

# f-string
f_string_time = timeit.timeit('f"数值:{num}"', setup='num=123.45', number=1000000)
print(f"F-string执行时间:{f_string_time:.6f}秒") # 约0.8秒

# format方法
format_time = timeit.timeit('"数值:{}".format(num)', setup='num=123.45', number=1000000)
print(f"Format执行时间:{format_time:.6f}秒") # 约3.1秒

# f-string比format方法快约3倍
print(f"F-string比format快{(format_time / f_string_time - 1)*100:.1f}%")

f-string 和 format 方法各有优劣,选择合适的格式化方式取决于具体应用场景

性能优势原因

  • f-string在编译时直接转换为高效字节码
  • 无需运行时解析模板,减少中间步骤
  • Python 3.12进一步优化了表达式处理

6.2 适用场景对比

场景 推荐方法 理由
现代项目开发 f-string 语法简洁,性能最佳,代码可读性高
旧代码维护 format 方法 兼容 Python 3.6 以下版本,确保代码向后兼容
动态参数场景 format 方法 支持从字典/列表动态获取参数,灵活性高
复杂表达式 f-string 支持直接嵌入表达式,无需额外代码
国际化应用 format 方法 更容易与国际化工具(如 gettext)集成

6.3 语法特性对比

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# f-string特性
# 直接嵌入表达式
print(f"5 + 10 = {5 + 10}")

# 支持函数调用
print(f"当前时间:{datetime.now():%H:%M}")

# Python 3.8+ 调试功能
x = 10
print(f"{x=}") # 输出:x=10

# Python 3.12+ 多行支持
print(f"""
这是一个多行f-string
包含换行符
可以跨多行书写
""")

# format方法特性
# 支持位置参数
print("用户:{0}, 年龄:{1}".format(name, age))

# 支持关键字参数
print("用户:{user}, 年龄:{years}".format(user="王八", years=35))

# 支持参数复用
print("用户:{0}, 年龄:{1}, 用户:{0}".format(name, age))

# 支持对象属性访问
class User:
def __init__(self, name, age):
self.name = name
self.age = age

user = User("李四", 30)
print("用户名:{0.name},年龄:{0.age}".format(user))

7. 输入处理

  • 从控制台获取用户数据
    input() 函数是 Python 中从控制台获取用户输入的标准方式,它始终返回字符串类型,开发者需要根据需求进行类型转换和验证

7.1 基础输入处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 简单输入
user_input = input("请输入内容:")
print(f"您输入的内容是:{user_input}")

# 多次输入
name = input("请输入姓名:")
age = input("请输入年龄:")
print(f"用户 {name},年龄 {age} 岁")

# 处理空输入
while True:
user_input = input("请输入非空内容:").strip()
if user_input:
break
print("输入不能为空,请重新输入!")

7.2 类型转换与异常处理📚

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# 安全获取整数输入
def get_integer(prompt, min_value=None, max_value=None):
"""获取整数输入。

Args:
prompt (str): 提示信息
min_value (int, optional): 最小值限制
max_value (int, optional): 最大值限制

Returns:
int: 转换后的整数值

Raises:
ValueError: 如果输入无法转换为整数
"""
while True:
try:
num = int(input(prompt))
if min_value is not None and num < min_value:
print(f"输入不能小于{min_value},请重新输入!")
continue
if max_value is not None and num > max_value:
print(f"输入不能大于{max_value},请重新输入!")
continue
return num
except ValueError:
print("输入无效,请输入一个整数!")

# 获取带范围的整数
player_count = get_integer("请输入玩家人数(1-4):", 1, 4)
print(f"玩家数量已设置为:{player_count}")

# 获取浮点数输入
def get_float(prompt, min_value=0, max_value=None):
"""获取浮点数输入。

Args:
prompt (str): 提示信息
min_value (float, optional): 最小值限制,默认为0
max_value (float, optional): 最大值限制

Returns:
float: 转换后的浮点数值

Raises:
ValueError: 如果输入无法转换为浮点数或超出范围
"""
while True:
try:
num = float(input(prompt))
if num < min_value:
print(f"输入不能小于{min_value},请重新输入!")
continue
if max_value is not None and num > max_value:
print(f"输入不能大于{max_value},请重新输入!")
continue
return num
except ValueError:
print("输入无效,请输入一个数字!")

# 获取工资和消费数据
monthly_salary = get_float("请输入月工资:")
daily_expense = get_float("请输入日均消费:", min_value=0)

8. 安全输入处理实践📚

用户输入是程序安全的主要威胁来源之一,必须采取适当的措施确保输入的安全性

8.1 避免使用 eval()

eval() 函数极其危险,因为它会执行任意 Python 代码,可能导致代码注入攻击

==安全警告==

永远不要在生产代码中使用 eval() 处理用户输入,因为它会执行任意 Python 代码,带来严重的安全风险。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 危险做法!
user_input = input("请输入Python表达式:")
# 这里user_input可以是任意代码,如os.remove("重要文件.txt")
result = eval(user_input) # 极其不安全!

# 安全替代方案
import ast

# 使用ast.literal_eval()代替eval()
user_input = input("请输入Python表达式:")
try:
safe_data = ast.literal_eval(user_input)
print(f"安全解析结果:{safe_data}")
except (ValueError, SyntaxError):
print("输入无效,无法解析!")

8.2 正则表达式验证

使用正则表达式可以精确控制输入的格式,防止恶意输入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import re

# 验证邮箱格式
def validate_email(email):
"""验证邮箱地址格式。

Args:
email (str): 要验证的邮箱地址

Returns:
bool: 如果邮箱格式有效,返回True;否则返回False
"""
pattern = r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$"
return bool(re.match(pattern, email))

# 验证用户名格式
def validate_username(username):
"""验证用户名格式。

Args:
username (str): 要验证的用户名

Returns:
bool: 如果用户名格式有效,返回True;否则返回False
"""
# 用户名只能包含字母、数字和下划线,长度2-20
pattern = r"^[a-zA-Z0-9_]{2,20}$"
return bool(re.match(pattern, username))

# 验证密码强度
def validate_password(password):
"""验证密码强度。

Args:
password (str): 要验证的密码

Returns:
bool: 如果密码符合要求,返回True;否则返回False
"""
# 至少8个字符,包含大写字母、小写字母、数字和特殊字符
pattern = r"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$"
return bool(re.match(pattern, password))

8.3 多层防御体系

建立多层防御体系可以显著提高输入安全性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import re
import ast

def safe_input(prompt, max_len=100, pattern=None, data_type=str):
"""安全获取用户输入。

Args:
prompt (str): 提示信息
max_len (int, optional): 最大允许长度,默认为100
pattern (re.Pattern, optional): 正则表达式验证模式
data_type (type, optional): 目标数据类型,默认为str

Returns:
any: 转换后的安全输入数据

Raises:
ValueError: 如果输入验证失败
"""
while True:
user_input = input(prompt).strip()

# 层级1:长度限制
if len(user_input) > max_len:
print(f"输入过长,最大允许 {max_len} 字符")
continue

# 层级2:正则表达式验证
if pattern and not re.fullmatch(pattern, user_input):
print("输入格式不符合要求,请重新输入!")
continue

# 层级3:类型转换与验证
try:
if data_type == int:
value = int(user_input)
elif data_type == float:
value = float(user_input)
elif data_type == list:
value = ast.literal_eval(user_input)
if not isinstance(value, list):
raise ValueError("输入不是列表")
elif data_type == dict:
value = ast.literal_eval(user_input)
if not isinstance(value, dict):
raise ValueError("输入不是字典")
else:
value = user_input

# 额外验证
if data_type == list and not 1 <= len(value) <= 10:
print("列表长度必须在1到10之间,请重新输入!")
continue
if data_type == dict and "name" not in value:
print("字典必须包含"name"键,请重新输入!")
continue

return value
except ValueError as e:
print(f"类型转换失败:{e},请重新输入!")

# 使用安全输入函数
email = safe_input("请输入邮箱地址:", pattern=r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$")
username = safe_input("请输入用户名:", pattern=r"^[a-zA-Z0-9_]{2,20}$")
password = safe_input("请输入密码:", pattern=r"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$")
age = safe_input("请输入年龄:", data_type=int, min_value=0, max_value=150)

print(f"注册信息:{username}, {email}, 年龄:{age}")

8.4 敏感信息输入

处理密码等敏感信息时,应使用专门的模块而非 input() 函数

1
2
3
4
5
6
7
8
9
10
11
import getpass

# 安全获取密码
password = getpass.getpass("请输入密码:")
confirm_password = getpass.getpass("请确认密码:")

if password != confirm_password:
print("两次输入的密码不一致,请重新注册!")
exit(1)

print("密码验证通过!")

9. 实际项目应用案例📚

1. 用户注册系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import getpass
import re
import ast
import datetime
from typing import Dict, Any

def validate_input(prompt: str, pattern: str = None, data_type: type = str,
min_len: int = 0, max_len: int = 100,
min_value: Any = None, max_value: Any = None) -> Any:
"""通用输入验证函数。

Args:
prompt (str): 提示信息
pattern (str, optional): 正则表达式验证模式,默认为None
data_type (type, optional): 目标数据类型,默认为str
min_len (int, optional): 最小长度限制,默认为0
max_len (int, optional): 最大长度限制,默认为100
min_value (Any, optional): 最小值限制,默认为None
max_value (Any, optional): 最大值限制,默认为None

Returns:
Any: 验证通过的输入值

Raises:
ValueError: 如果输入验证失败
"""
while True:
try:
user_input = input(prompt).strip()

# 长度验证
if len(user_input) < min_len:
print(f"输入过短,至少需要 {min_len} 个字符")
continue
if len(user_input) > max_len:
print(f"输入过长,最多允许 {max_len} 个字符")
continue

# 正则表达式验证
if pattern and not re.fullmatch(pattern, user_input):
print("输入格式不符合要求,请重新输入!")
continue

# 类型转换
if data_type == int:
value = int(user_input)
elif data_type == float:
value = float(user_input)
elif data_type in (list, dict, tuple):
value = ast.literal_eval(user_input)
if not isinstance(value, data_type):
raise ValueError(f"输入必须是{data_type.__name__}类型")
else:
value = user_input

# 值范围验证
if min_value is not None and value < min_value:
print(f"输入值不能小于 {min_value}")
continue
if max_value is not None and value > max_value:
print(f"输入值不能大于 {max_value}")
continue

return value

except ValueError as e:
print(f"输入无效:{e},请重新输入!")

def register_user() -> Dict[str, Any]:
"""注册新用户。

Returns:
dict: 包含用户信息的字典
"""
print("=== 用户注册 ===")

# 获取用户名
username_pattern = r"^[a-zA-Z0-9_]{2,20}$"
username = validate_input(
"请输入用户名(仅限字母、数字、下划线,2-20个字符):",
pattern=username_pattern,
data_type=str
)

# 获取邮箱
email_pattern = r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$"
email = validate_input(
"请输入邮箱地址:",
pattern=email_pattern,
data_type=str
)

# 获取年龄
age = validate_input(
"请输入年龄(0-150岁):",
data_type=int,
min_value=0,
max_value=150
)

# 获取密码(使用getpass模块)
import getpass
password_pattern = r"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$"
password = getpass.getpass("请输入密码(至少8位,包含大小写字母、数字和特殊字符):")
while not re.fullmatch(password_pattern, password):
print("密码不符合安全要求,请重新输入!")
password = getpass.getpass("请输入密码:")

# 确认密码
confirm_password = getpass.getpass("请再次输入密码:")
if confirm_password != password:
print("两次输入的密码不一致,请重新注册!")
exit(1)

# 获取注册时间
registration_time = datetime.datetime.now()

# 创建用户信息字典
user_info = {
"username": username,
"email": email,
"age": age,
"registration_time": registration_time.strftime("%Y-%m-%d %H:%M:%S")
}

# 打印欢迎信息
print(f"\n=== 欢迎 {username}! ===")
print(f"您的邮箱:{email}")
print(f"您的年龄:{age}")
print(f"注册时间:{registration_time:%Y-%m-%d %H:%M}")
print("注册成功!")

return user_info

# 执行注册功能
user = register_user()

2. 数据处理工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import ast
import statistics
import re

def safe_float_input(prompt: str, min_value: float = None, max_value: float = None) -> float:
"""安全获取浮点数输入。

Args:
prompt (str): 提示信息
min_value (float, optional): 最小值限制,默认为None
max_value (float, optional): 最大值限制,默认为None

Returns:
float: 验证通过的浮点数值

Raises:
ValueError: 如果输入验证失败
"""
return validate_input(
prompt,
data_type=float,
min_value=min_value,
max_value=max_value
)

def safe_list_input(prompt: str, element_type: type = int) -> list:
"""安全获取列表输入。

Args:
prompt (str): 提示信息
element_type (type, optional): 列表元素类型,默认为int

Returns:
list: 验证通过的列表

Raises:
ValueError: 如果输入验证失败
"""
while True:
try:
user_input = input(prompt).strip()

# 正则表达式验证列表格式
list_pattern = r"^\[(?:\s*" + re.escape(element_type.__name__) + r"\s*,?\s*)+\]$"
if not re.fullmatch(list_pattern, user_input):
print(f"输入格式不符合要求,应为类似 [1, 2, 3] 的{element_type.__name__}列表,请重新输入!")
continue

# 安全解析列表
value = ast.literal_eval(user_input)

# 验证元素类型
if not isinstance(value, list):
raise ValueError("输入不是列表类型")

if not all(isinstance(item, element_type) for item in value):
raise ValueError(f"列表中包含非{element_type.__name__}类型元素")

return value

except (ValueError, SyntaxError) as e:
print(f"输入无效:{e},请重新输入!")

def process_finances():
"""财务数据处理工具。"""

# 获取收入数据
print("\n=== 收入数据录入 ===")
income_data = safe_list_input("请输入月收入数据(单位:元,如 [5000, 6000, 5500]):", float)

# 获取支出数据
print("\n=== 支出数据录入 ===")
expense_data = safe_list_input("请输入月支出数据(单位:元,如 [3000, 3500, 3200]):", float)

# 计算财务指标
print("\n=== 财务分析 ===")
print("正在计算财务指标...")

# 收入分析
total_income = sum(income_data)
avg_income = statistics.mean(income_data)
max_income = max(income_data)
min_income = min(income_data)

# 支出分析
total_expense = sum(expense_data)
avg_expense = statistics.mean(expense_data)
max_expense = max(expense_data)
min_expense = min(expense_data)

# 利润分析
profit = [inc - exp for inc, exp in zip(income_data, expense_data)]
total_profit = sum(profit)
avg_profit = statistics.mean(profit)
if any(p < 0 for p in profit):
loss_months = [i+1 for i, p in enumerate(profit) if p < 0]
print(f"注意:第 {', '.join(map(str, loss_months))} 个月出现亏损")

# 打印财务报告
print("\n=== 财务报告 ===")
print(f"月份:{len(income_data)}")
print(f"总收入:{total_income:,.2f} 元")
print(f"平均收入:{avg_income:,.2f} 元")
print(f"最高收入:{max_income:,.2f} 元")
print(f"最低收入:{min_income:,.2f} 元")

print(f"总支出:{total_expense:,.2f} 元")
print(f"平均支出:{avg_expense:,.2f} 元")
print(f"最高支出:{max_expense:,.2f} 元")
print(f"最低支出:{min_expense:,.2f} 元")

print(f"总利润:{total_profit:,.2f} 元")
print(f"平均利润:{avg_profit:,.2f} 元")

# 使用f-string的格式控制
print("\n=== 详细财务数据 ===")
print("月份\t收入\t支出\t利润")

for month, inc, exp, pro in enumerate(zip(income_data, expense_data, profit), 1):
print(f"{month}\t{inc[0]:>9,.2f}\t{inc[1]:>9,.2f}\t{inc[2]:>9,.2f}")

# 使用format方法生成对齐报告
print("\n=== 对比分析 ===")
print("收入与支出对比:")

# 使用format方法对齐文本
print("{:<10} {:>15} {:>15}".format("指标", "收入", "支出"))
print("{:<10} {:>15,.2f} {:>15,.2f}".format("总和", total_income, total_expense))
print("{:<10} {:>15,.2f} {:>15,.2f}".format("平均", avg_income, avg_expense))
print("{:<10} {:>15,.2f} {:>15,.2f}".format("最高", max_income, max_expense))
print("{:<10} {:>15,.2f} {:>15,.2f}".format("最低", min_income, min_expense))

process_finances()

3. 交互式计算器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import ast
import operator
from datetime import datetime

# 支持的操作符
supported_operations = {
"+": operator.add,
"-": operator.sub,
"*": operator.mul,
"/": operator.truediv,
"**": operator.pow,
"%": operator.mod,
"^": operator.xor,
}

def calculator():
"""交互式计算器程序。"""
print("=== 欢迎使用交互式计算器 ===")
print("支持的操作:+, -, *, /, **, %, ^")
print("输入q退出程序")

while True:
# 获取表达式
expression = input("\n请输入表达式(如 5 + 3):")

if expression.lower() == "q":
print("感谢使用计算器!")
print(f"程序结束时间:{datetime.now():%H:%M:%S}")
break

# 使用正则表达式分割表达式
import re
match = re.match(r"^\s*(\d+\.?\d*)\s*([+\-*/%^]+)\s*(\d+\.?\d*)\s*$", expression)

if not match:
print("错误:表达式格式不正确,请使用格式:数字 操作符 数字")
continue

# 提取操作数和操作符
num1 = float(match.group(1))
op = match.group(2).strip()
num2 = float(match.group(3))

# 检查操作符
if op not in supported_operations:
print(f"错误:不支持操作符 '{op}'")
continue

# 执行计算
try:
result = supported_operations[op](num1, num2)
except ZeroDivisionError:
print("错误:除数不能为零!")
continue

# 使用f-string显示结果
print(f"\n计算结果:{num1} {op} {num2} = {result:.4f}")

# 使用format方法生成详细报告
report = """
=== 计算详细信息 ===
输入表达式:{expression!r}
操作数1:{num1:.4f}
操作符:{op!r}
操作数2:{num2:.4f}
结果:{result:.4f}
计算时间:{time:%Y-%m-%d %H:%M:%S}
"""
print(report.format(
expression=expression,
num1=num1,
num2=num2,
op=op,
result=result,
time=datetime.now()
))

# 使用f-string的调试功能
print(f"\n当前计算结果:{result=}")
print(f"计算时间:{datetime.now()=}")

# 运行计算器
calculator()

10. 实践与建议📚

1. 字符串格式化选择建议

基于项目需求和 Python 版本选择合适的字符串格式化方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# 新项目首选f-string
def calculate_i(x, y):
"""计算两个数的和。

Args:
x (int or float): 第一个加数
y (int or float): 第二个加数

Returns:
int or float: 两个数的和
"""
return x + y

# 需要兼容Python 3.6以下版本使用format
def backward_compatible_format(x, y):
"""计算两个数的和(兼容旧版)。

Args:
x (int or float): 第一个加数
y (int or float): 第二个加数

Returns:
str: 格式化后的结果字符串
"""
return "x + y = {0}".format(x + y)

# 需要动态参数使用format
def dynamic_parameters():
"""演示动态参数格式化。"""
data = {"name": "李四", "age": 30, "score": 95.5}
return "学生信息:{0[name]},年龄:{0[age]},成绩:{0[score]:.2f}".format(data)

# 复杂格式化混合使用
def complex_formatting():
"""演示复杂格式化场景。"""
from datetime import datetime

# 使用f-string获取时间
now = datetime.now()
name = "王五"
score = 85.75

# 使用format方法生成报告
report = """
=== 学生成绩报告 ===
姓名:{0}
成绩:{1:.2f}
状态:{2}
日期:{3:%Y-%m-%d}
"""
status = "优秀" if score >= 90 else "良好" if score >= 80 else "合格"

return report.format(name, score, status, now)

2. 输入处理实践

确保输入处理安全、健壮且用户友好

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
import re
import ast
import getpass
import datetime
from contextlib import suppress

def prompt_for_float(prompt: str, min_value: float = None, max_value: float = None) -> float:
"""安全获取浮点数输入。

Args:
prompt (str): 提示信息
min_value (float, optional): 最小值限制,默认为None
max_value (float, optional): 最大值限制,默认为None

Returns:
float: 验证通过的浮点数值

Raises:
ValueError: 如果输入验证失败
"""
while True:
try:
value = float(input(prompt).strip())

if min_value is not None and value < min_value:
print(f"错误:输入不能小于 {min_value}")
continue

if max_value is not None and value > max_value:
print(f"错误:输入不能大于 {max_value}")
continue

return value
except ValueError:
print("错误:请输入一个有效的数字")

def prompt_for_integer_range(prompt: str, min_val: int, max_val: int) -> int:
"""获取指定范围内的整数输入。

Args:
prompt (str): 提示信息
min_val (int): 最小值
max_val (int): 最大值

Returns:
int: 验证通过的整数值

Raises:
ValueError: 如果输入验证失败
"""
while True:
try:
value = int(input(prompt).strip())
if min_val <= value <= max_val:
return value
print(f"错误:输入必须在 {min_val}{max_val} 之间")
except ValueError:
print(f"错误:请输入一个整数({min_val}-{max_val})")

def prompt_for_safe_list(prompt: str, element_type: type = int) -> list:
"""安全获取列表输入。

Args:
prompt (str): 提示信息
element_type (type, optional): 列表元素类型,默认为int

Returns:
list: 验证通过的列表

Raises:
ValueError: 如果输入验证失败
"""
while True:
try:
user_input = input(prompt).strip()

# 正则表达式验证列表格式
list_pattern = r"^\[(?:\s*" + re.escape(element_type.__name__) + r"\s*,?\s*)+\]$"
if not re.fullmatch(list_pattern, user_input):
print(f"错误:输入格式不符合要求,应为类似 [1, 2, 3] 的{element_type.__name__}列表")
continue

# 安全解析列表
value = ast.literal_eval(user_input)

# 验证元素类型
if not isinstance(value, list):
raise ValueError("输入不是列表类型")

if not all(isinstance(item, element_type) for item in value):
raise ValueError(f"列表中包含非{element_type.__name__}类型元素")

return value

except (ValueError, SyntaxError) as e:
print(f"错误:输入无效,{e},请重新输入")

def prompt_for_safe_dict(prompt: str, required_keys: list = None) -> dict:
"""安全获取字典输入。

Args:
prompt (str): 提示信息
required_keys (list, optional): 必须包含的键,默认为None

Returns:
dict: 验证通过的字典

Raises:
ValueError: 如果输入验证失败
"""
while True:
try:
user_input = input(prompt).strip()

# 正则表达式验证字典格式
dict_pattern = r"^\{(?:\s*[a-zA-Z_]\w+\s*:\s*[^\s,]+,?\s*)+\}$"
if not re.fullmatch(dict_pattern, user_input):
print("错误:输入格式不符合要求,应为类似 {'name': '张三', 'age': 25} 的字典")
continue

# 安全解析字典
value = ast.literal_eval(user_input)

# 验证是否为字典
if not isinstance(value, dict):
raise ValueError("输入不是字典类型")

# 验证必须的键
if required_keys:
missing_keys = [key for key in required_keys if key not in value]
if missing_keys:
raise ValueError(f"缺少必要键:{', '.join(missing_keys)}")

return value

except (ValueError, SyntaxError) as e:
print(f"错误:输入无效,{e},请重新输入")

def prompt_for_safe_username(prompt: str, min_len: int = 2, max_len: int = 20) -> str:
"""获取安全的用户名输入。

Args:
prompt (str): 提示信息
min_len (int, optional): 最小长度,默认为2
max_len (int, optional): 最大长度,默认为20

Returns:
str: 验证通过的用户名

Raises:
ValueError: 如果输入验证失败
"""
while True:
username = input(prompt).strip()

if not username:
print(f"错误:用户名不能为空")
continue

if not min_len <= len(username) <= max_len:
print(f"错误:用户名长度必须在 {min_len}{max_len} 之间")
continue

if not re.fullmatch(r"^[a-zA-Z0-9_]+$", username):
print("错误:用户名只能包含字母、数字和下划线")
continue

return username

def prompt_for_safe_password(prompt: str) -> str:
"""获取安全密码输入。

Args:
prompt (str): 提示信息

Returns:
str: 验证通过的密码

Raises:
ValueError: 如果输入验证失败
"""
while True:
password = getpass.getpass(prompt)

if len(password) < 8:
print("错误:密码至少需要8个字符")
continue

if not re.search(r"[a-z]", password):
print("错误:密码必须包含至少一个小写字母")
continue

if not re.search(r"[A-Z]", password):
print("错误:密码必须包含至少一个大写字母")
continue

if not re.search(r"\d", password):
print("错误:密码必须包含至少一个数字")
continue

if not re.search(r"[@$!%*?&]", password):
print("错误:密码必须包含至少一个特殊字符")
continue

confirm_password = getpass.getpass("请再次输入密码:")
if password != confirm_password:
print("错误:两次输入的密码不一致")
continue

return password

3. 实际项目中的综合应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import re
import ast
import getpass
import datetime
from typing import Dict, Any
import statistics

def main():
"""主程序入口。"""
print(f"{'='*30}")
print(f"{' 财务管理系统 v2.1 ':^30}")
print(f"{'='*30}")
print(f"启动时间:{datetime.now():%Y-%m-%d %H:%M:%S}")
print()

# 用户注册
print("=== 用户注册 ===")
username = prompt_for_safe_username("用户名:")
password = prompt_for_safe_password("密码:")
email = prompt_for_safe_email("邮箱:")
age = prompt_for_integer_range("年龄(18-65):", 18, 65)

print()
print(f"{'='*30}")
print(f"{' 欢迎 {username}! ':^30}")
print(f"{'='*30}")
print()

# 数据录入
print("=== 月度财务数据录入 ===")

# 收入数据
income_prompt = """
请输入本月收入数据(以逗号分隔,如 5000, 6000, 5500)
输入格式:[数字, 数字, ...]
> """
income_data = prompt_for_safe_list(income_prompt, float)

# 支出数据
expense_prompt = """
请输入本月支出数据(以逗号分隔,如 3000, 3500, 3200)
输入格式:[数字, 数字, ...]
> """
expense_data = prompt_for_safe_list(expense_prompt, float)

# 验证数据长度一致
if len(income_data) != len(expense_data):
print(f"错误:收入和支出数据长度不一致(收入:{len(income_data)},支出:{len(expense_data)})")
exit(1)

# 财务分析
print("\n=== 财务分析 ===")
print("正在计算财务指标...")

# 收入分析
total_income = sum(income_data)
avg_income = statistics.mean(income_data)
max_income = max(income_data)
min_income = min(income_data)

# 支出分析
total_expense = sum(expense_data)
avg_expense = statistics.mean(expense_data)
max_expense = max(expense_data)
min_expense = min(expense_data)

# 利润分析
profit = [inc - exp for inc, exp in zip(income_data, expense_data)]
total_profit = sum(profit)
avg_profit = statistics.mean(profit)

# 生成财务报告
report = f"""
=== 财务报告 ===
用户:{username}
报告日期:{datetime.now():%Y-%m-%d}

月份:{len(income_data)}

总收入:{total_income:,.2f}
平均收入:{avg_income:,.2f}
最高收入:{max_income:,.2f}
最低收入:{min_income:,.2f}

总支出:{total_expense:,.2f}
平均支出:{avg_expense:,.2f}
最高支出:{max_expense:,.2f}
最低支出:{min_expense:,.2f}

总利润:{total_profit:,.2f}
平均利润:{avg_profit:,.2f}

数据详情:
"""
print(report)

# 使用f-string生成表格
print("\n财务数据表格:")
print("{:<10} {:>15} {:>15} {:>15}".format("月份", "收入", "支出", "利润"))
print("-"*50)

for month, (inc, exp, pro) in enumerate(zip(income_data, expense_data, profit), 1):
print("{:<10} {:>15,.2f} {:>15,.2f} {:>15,.2f}".format(f"第{month}月", inc, exp, pro))

# 使用f-string的调试功能
print(f"\n当前财务数据:{income_data=}, {expense_data=}")
print(f"计算结果:{total_profit=:.2f}")

# 使用format方法生成总结
summary = """
=== 财务总结 ===
总收入:{0:.2f} 元
总支出:{1:.2f} 元
总利润:{2:+.2f} 元
"""
print(summary.format(total_income, total_expense, total_profit))
print()
print(f"程序已执行 {datetime.now() - start_time} 秒")
print("感谢使用本系统!")

if __name__ == "__main__":
start_time = datetime.now()
main()

11. 文件读写📚

  • open 函数
  • with 语句

11.1 文件操作基础

  • open 函数详解

11.1.1 open 函数基本语法

open()函数是 Python 中文件操作的起点,它返回一个文件对象,用于后续的读写操作。基本语法结构如下:

1
2
3
4
5
6
7
8
9
10
file_object = open(
file_path, # 文件路径(字符串类型)
mode='r', # 打开模式(默认为只读)
encoding=None, # 编码方式(文本模式下使用)
errors=None, # 编码错误处理方式
buffering=-1, # 缓冲区大小(-1表示使用默认值)
newline=None, # 换行符处理方式
closefd=True, # 是否自动关闭文件描述符
opener=None # 自定义打开函数
)

关键参数说明

参数 默认值 作用
file_path 必须指定 文件的路径,可以是相对路径或绝对路径
mode ‘r’ 文件打开模式,决定可进行的操作
encoding None 指定文本文件的编码方式,如’utf-8’
buffering -1 控制文件的缓冲策略,0 表示无缓冲,1 表示行缓冲,>1 表示指定缓冲区大小
newline None 控制换行符处理,表示不转换

11.1.2 文件打开模式详解

Python的文件打开模式决定了可对文件进行的操作类型,常见模式组合及行为如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 只读模式(默认)
with open('file.txt', 'r') as f:
content = f.read()

# 写入模式(覆盖文件内容)
with open('output.txt', 'w') as f:
f.write('Hello, World!') # 文件不存在则创建,存在则清空内容

# 追加模式(保留原有内容)
with open('log.txt', 'a') as f:
f.write('\nNew entry added') # 内容追加到文件末尾

# 读写模式
with open('data.txt', 'r+'):
# 允许读取和写入,指针位置影响操作

# 二进制模式
with open('image.jpg', 'rb') as f:
binary_data = f.read() # 返回字节对象,而非字符串

模式参数完整对照表

模式 类型 可执行操作 文件不存在时 文件存在时
r 文本 只读 报错 FileNotFoundError 从开头读取
w 文本 写入 创建新文件 清空现有内容
a 文本 追加 创建新文件 在文件末尾追加
r+ 文本 读写 报错 保留内容,可修改
w+ 文本 读写 创建新文件 清空内容
a+ 文本 读写 创建新文件 保留内容,追加写入
rb 二进制 只读 报错 从开头读取
wb 二进制 写入 创建新文件 清空内容
ab 二进制 追加 创建新文件 保留内容,追加写入
r+b 二进制 读写 报错 保留内容,可修改
w+b 二进制 读写 创建新文件 清空内容
a+b 二进制 读写 创建新文件 保留内容,追加写入

11.1.3 编码处理与错误处理

编码参数在文本文件操作中至关重要,特别是在处理中文等非英文内容时:

1
2
3
4
5
6
7
# 指定编码方式
with open('chinese.txt', 'r', encoding='utf-8') as f:
content = f.read() # 正确读取中文内容

# 处理编码错误
with open('corrupted.txt', 'r', encoding='utf-8', errors='replace') as f:
content = f.read() # 无法识别的字符会被替换为'?'

错误处理选项

  • ‘strict’(默认):遇到编码错误时抛出UnicodeError
  • ‘ignore’:忽略无法解码的字节
  • ‘replace’:用占位符(如’?’)替换无法解码的字节
  • ‘xmlcharrefreplace’:用XML字符引用替换无法解码的字符
  • ‘backslashreplace’:用反斜杠转义序列替换无法解码的字节

11.2 with 语句

  • 安全的文件操作保障

1. with 语句的工作原理

with 语句是 Python 的上下文管理器,它通过__enter____exit__方法确保资源在使用后被正确释放。对于文件对象,__exit__方法会自动调用file.close()

1
2
3
4
5
6
7
8
9
# with语句内部机制
file = open('data.txt', 'r')
try:
# 执行with代码块
content = file.read()
print(content)
finally:
# 自动执行关闭操作
file.close()

2. 与传统 try-except-finally 的对比

传统方式

1
2
3
4
5
6
7
8
file = open('data.txt', 'r')
try:
content = file.read()
print(content)
except Exception as e:
print(f"读取文件时出错: {e}")
finally:
file.close() # 确保文件被关闭

with 语句方式(更简洁安全):

1
2
3
4
5
6
try:
with open('data.txt', 'r') as file:
content = file.read()
print(content)
except Exception as e:
print(f"读取文件时出错: {e}")

优势对比

  • 代码简洁性:with语句减少了样板代码,使核心逻辑更突出
  • 异常安全性:即使代码块中抛出异常,文件也会被自动关闭
  • 资源管理可靠性:避免了因忘记关闭文件导致的资源泄漏
  • 可读性提升:明确界定资源的获取和释放范围

练习:


第一部分

  1. 写出 Python 中用于等待用户输入的函数,并举例说明如何获取用户输入并赋值给变量 name

  2. 请写出在同一行书写多条 Python 语句的正确语法,并给出一个包含 2 条赋值语句的示例。

  3. 写出 Python 中用于输出内容到控制台的函数,并完成以下任务:

    • 输出字符串 Hello, Python!
    • 输出变量 age 的值,并在前面加上提示文字 我的年龄是:
  4. 以下代码是否能在同一行正常运行?如果不能,请说明原因并改正:

1
2
a = 10 b = 20
print(a + b)
  1. 补全代码:让程序先获取用户输入的数字,再将其转换为整数并输出:
1
2
3
num = ____("请输入一个数字:")
num_int = ____(num)
____("你输入的数字是:", num_int)

第二部分

  1. 思考:input() 函数获取的用户输入默认是什么数据类型?如果想获取数字,需要做什么处理?
  2. 尝试用一行代码完成:获取用户输入的两个数字,计算它们的和并输出(提示:可使用分号和类型转换)。
  3. 对比 print(a, b)print(a + b) 的输出区别,分别举例说明(假设 a=10, b=20)。
  4. 如何让 print() 函数在输出后不自动换行?请写出对应的参数用法。
  5. 思考:如果在同一行写多条语句时,其中一条语句报错,会对其他语句产生什么影响?试举一例验证。

参考答案


第一部分

  1. 等待用户输入
    使用 input() 函数,示例:
1
name = input("请输入你的名字:")
  1. 同一行显示多条语句
    使用分号 ; 分隔,示例:
1
a = 10; b = 20
  1. 输出
    使用 print() 函数:
1
2
3
4
5
# 输出字符串
print("Hello, Python!")
# 输出带提示的变量
age = 18
print("我的年龄是:", age)
  1. 同一行语句错误修正
    原代码不能正常运行,原因是多条语句未用分号分隔。
    改正:
1
2
a = 10; b = 20
print(a + b)
  1. 补全代码
1
2
3
num = input("请输入一个数字:")
num_int = int(num)
print("你输入的数字是:", num_int)

第二部分

  1. input() 数据类型
    input() 获取的输入默认是字符串(str)类型
    若要获取数字,需要用 int()float() 进行类型转换,例如:
1
num = int(input("请输入整数:"))
  1. 一行代码实现两数求和
1
a = int(input("输入第一个数:")); b = int(input("输入第二个数:")); print(a + b)
  1. print(a, b)print(a + b) 区别

    • print(a, b):会用空格分隔输出两个值,例:10 20
    • print(a + b):会先计算表达式结果再输出,例:30(若为字符串则是拼接,如 "10"+"20""1020"
  2. print() 不自动换行
    使用 end 参数,示例:

1
2
print("Hello", end=" ")
print("World") # 输出:Hello World(在同一行)
  1. 同一条语句报错的影响
    若某条语句报错,会导致整个代码块中断执行,后续语句不会运行。
1
a = 10; b = 20 / 0; print(a + b)  # 除零错误,print 不会执行