1. Python输入输出的基础概念
作为一名从2010年开始使用Python的老程序员,我见证了Python输入输出方式的多次演变。对于初学者来说,掌握好输入输出是编程的第一步,就像学开车要先学会踩油门和刹车一样基础但重要。
Python中的输入输出主要涉及三个核心对象:
- 标准输入(stdin):通常对应键盘输入
- 标准输出(stdout):通常对应屏幕输出
- 标准错误(stderr):用于输出错误信息
在Python中,我们最常用的是内置的input()函数获取用户输入,print()函数进行输出。但真正让Python强大的,是它丰富的格式化输出能力。下面这个简单的例子展示了最基本的用法:
python复制name = input("请输入你的名字: ") # 获取输入
print("你好,", name) # 输出结果
注意:在Python 2.x中,input()的行为与Python 3.x不同。Python 2.x的input()会直接执行输入的表达式,存在安全隐患,建议使用raw_input()。这也是为什么我强烈推荐新手直接从Python 3开始学习。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 传统字符串格式化方法
2.1 %操作符格式化
这是Python最早的字符串格式化方法,借鉴自C语言的printf风格。虽然现在不推荐作为首选,但在维护老代码时仍会遇到。
python复制# 基本用法
print("我叫%s,今年%d岁,身高%.2f米" % ("张三", 25, 1.753))
# 字典形式
data = {"name": "李四", "age": 30}
print("姓名:%(name)s 年龄:%(age)d" % data)
格式说明符:
- %s:字符串
- %d:十进制整数
- %f:浮点数
- %x:十六进制整数
- %%:百分号本身
实战经验:当需要格式化的变量较多时,建议使用字典形式,这样即使顺序调整也不会出错。我在维护一个老项目时,就遇到过因为参数顺序调整导致的bug,改用字典形式后问题迎刃而解。
2.2 str.format()方法
Python 2.6引入的.format()方法提供了更强大的格式化能力,也是我在Python 3.6之前最常用的方式。
python复制# 位置参数
print("{}的{}成绩是{:.1f}分".format("张三", "数学", 95.5))
# 关键字参数
print("{name}的{subject}成绩是{score:.1f}分".format(
name="李四", subject="物理", score=88.5))
# 格式化数字
print("十进制:{:d} 十六进制:{:x} 二进制:{:b}".format(255, 255, 255))
# 对齐与填充
print("{:*^20}".format("居中")) # ********居中********
print("{:<20}".format("左对齐")) # 左对齐
print("{:>20}".format("右对齐")) # 右对齐
.format()的优势:
- 更直观的位置参数和关键字参数
- 支持复杂的格式规范(对齐、填充、数字格式化等)
- 可复用参数(如
{0} {0} {1}) - 更好的可读性
我在实际项目中发现,对于需要本地化的字符串,.format()特别有用,因为可以轻松调整参数顺序而不影响代码逻辑。
3. 现代字符串格式化:f-string
Python 3.6引入的f-string(格式化字符串字面量)彻底改变了游戏规则,这也是我现在最推荐的方式。
3.1 基础用法
python复制name = "王五"
age = 28
height = 1.82
# 直接嵌入变量
print(f"{name}今年{age}岁,身高{height:.2f}米")
# 执行表达式
print(f"明年{name}就{age + 1}岁了")
# 调用方法
print(f"名字大写:{name.upper()}")
f-string的特点:
- 语法简洁,直接在字符串前加f或F
- 变量名直接嵌入{}中
- 支持任意有效Python表达式
- 执行效率比%和.format()更高
3.2 高级特性
python复制# 数字格式化
num = 123456.789
print(f"千分位: {num:,}") # 123,456.789
print(f"保留两位: {num:.2f}") # 123456.79
print(f"科学计数: {num:e}") # 1.234568e+05
# 对齐与填充
text = "Python"
print(f"{text:*^20}") # *******Python*******
print(f"{text:_<20}") # Python______________
print(f"{text:>20}") # Python
# 日期格式化
from datetime import datetime
now = datetime.now()
print(f"当前时间: {now:%Y-%m-%d %H:%M:%S}") # 2023-08-20 14:30:15
# 调试功能(Python 3.8+)
value = 42
print(f"{value=}") # 输出: value=42
性能提示:我做过测试,f-string的执行速度比%操作符快约1.5倍,比.format()快约2倍。在对性能敏感的场景(如循环中大量字符串操作),f-string有明显优势。
4. 输入处理与验证
获取用户输入只是第一步,实际项目中必须对输入进行验证和处理。这是我多年工作积累的经验之谈。
4.1 基本输入处理
python复制# 处理数字输入
age = input("请输入年龄: ")
try:
age = int(age)
print(f"你输入的年龄是: {age}")
except ValueError:
print("请输入有效的数字年龄")
# 多值输入
values = input("请输入多个数字,用空格分隔: ")
numbers = [int(x) for x in values.split() if x.isdigit()]
print(f"你输入的数字有: {numbers}")
4.2 高级输入技巧
python复制# 密码输入(不显示)
import getpass
password = getpass.getpass("请输入密码: ")
print(f"密码长度: {len(password)}")
# 超时输入(Unix-like系统)
import signal
def timeout_handler(signum, frame):
raise TimeoutError("输入超时")
signal.signal(signal.SIGALRM, timeout_handler)
signal.alarm(5) # 5秒超时
try:
data = input("请在5秒内输入: ")
signal.alarm(0) # 取消超时
except TimeoutError:
print("\n输入超时,使用默认值")
data = "default"
4.3 输入验证模式
在实际项目中,我通常会封装一个输入验证函数:
python复制def get_valid_input(prompt, input_type=str, validator=None, max_retry=3):
for _ in range(max_retry):
try:
value = input(prompt)
if input_type != str:
value = input_type(value)
if validator and not validator(value):
raise ValueError
return value
except ValueError:
print(f"无效输入,请重新输入({_ + 1}/{max_retry})")
raise ValueError("超过最大重试次数")
# 使用示例
age = get_valid_input("请输入年龄(18-60): ", int, lambda x: 18 <= x <= 60)
print(f"验证通过的年龄: {age}")
5. 文件输入输出实战
Python的输入输出不仅限于控制台,文件操作也是重要部分。下面分享我在实际项目中的文件IO经验。
5.1 基本文件操作
python复制# 写入文件
with open("example.txt", "w", encoding="utf-8") as f:
f.write("第一行内容\n")
f.write(f"格式化写入: {42}\n")
print("通过print写入", file=f) # print重定向到文件
# 读取文件
with open("example.txt", "r", encoding="utf-8") as f:
content = f.read() # 全部读取
print("文件内容:")
print(content)
# 按行读取
with open("example.txt", "r", encoding="utf-8") as f:
for line_num, line in enumerate(f, 1):
print(f"{line_num}: {line.strip()}")
5.2 CSV文件处理
python复制import csv
# 写入CSV
with open("data.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerow(["姓名", "年龄", "城市"])
writer.writerow(["张三", 25, "北京"])
writer.writerow(["李四", 30, "上海"])
# 读取CSV
with open("data.csv", "r", encoding="utf-8") as f:
reader = csv.reader(f)
headers = next(reader)
print(f"表头: {headers}")
for row in reader:
print(f"数据: {row}")
# 字典形式读写(推荐)
with open("data_dict.csv", "w", newline="", encoding="utf-8") as f:
fieldnames = ["name", "age", "city"]
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
writer.writerow({"name": "王五", "age": 28, "city": "广州"})
with open("data_dict.csv", "r", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
print(f"{row['name']} 住在 {row['city']}")
文件编码经验:在Windows下处理中文文件时,经常会遇到编码问题。我强烈建议始终明确指定encoding="utf-8",除非有特殊需求。曾经因为编码问题,我花了整整一天时间排查一个数据乱码问题。
6. 高级输出控制技巧
6.1 重定向标准输出
python复制import sys
from io import StringIO
# 捕获输出
old_stdout = sys.stdout
sys.stdout = buffer = StringIO()
print("这段输出会被捕获")
print("而不是显示在屏幕上")
sys.stdout = old_stdout # 恢复
captured = buffer.getvalue()
print("捕获的输出:")
print(captured)
6.2 彩色输出
python复制# 使用ANSI转义码
class Colors:
RED = "\033[91m"
GREEN = "\033[92m"
YELLOW = "\033[93m"
BLUE = "\033[94m"
END = "\033[0m"
print(f"{Colors.RED}红色警告{Colors.END}")
print(f"{Colors.GREEN}成功信息{Colors.END}")
# 使用colorama库(跨平台方案)
from colorama import Fore, Back, Style, init
init() # Windows下需要初始化
print(f"{Fore.RED}红色文本{Style.RESET_ALL}")
print(f"{Back.GREEN}绿色背景{Style.RESET_ALL}")
6.3 进度条显示
python复制import time
from tqdm import tqdm
# 简单进度条
for i in tqdm(range(100)):
time.sleep(0.02) # 模拟工作
# 自定义进度条
progress = tqdm(total=1000, desc="处理中")
for i in range(100):
progress.update(10) # 每次更新10
time.sleep(0.1)
progress.close()
我在处理大数据文件时经常使用进度条,特别是当处理时间较长时,给用户一个进度反馈非常重要。tqdm是我用过最顺手的进度条库,支持嵌套进度条、自定义格式等高级功能。
7. 性能优化与常见问题
7.1 字符串连接性能
python复制# 不推荐:频繁使用+连接字符串
result = ""
for i in range(10000):
result += str(i) # 每次创建新字符串
# 推荐:使用join
parts = []
for i in range(10000):
parts.append(str(i))
result = "".join(parts)
# 或者使用生成器表达式
result = "".join(str(i) for i in range(10000))
7.2 格式化性能比较
我做过一个简单的性能测试(Python 3.9):
python复制import timeit
def test_percent():
name = "Alice"
age = 25
return "%s is %d years old" % (name, age)
def test_format():
name = "Alice"
age = 25
return "{} is {} years old".format(name, age)
def test_fstring():
name = "Alice"
age = 25
return f"{name} is {age} years old"
print("百分号: ", timeit.timeit(test_percent, number=1000000))
print("format: ", timeit.timeit(test_format, number=1000000))
print("f-string:", timeit.timeit(test_fstring, number=1000000))
典型结果:
- 百分号: 0.35秒
- format: 0.45秒
- f-string: 0.25秒
7.3 常见问题解决
问题1:中文对齐问题
python复制# 中英混合时对齐不准
print(f"{'名字':<10}{'年龄':<10}") # 中文字符宽度问题
print(f"{'name':<10}{'age':<10}")
# 解决方案:使用中文空格或计算宽度
def chinese_pad(text, width, fillchar=" "):
# 粗略计算:中文占2个英文字符宽度
ch_width = sum(2 if ord(c) > 127 else 1 for c in text)
return text.ljust(width - (ch_width - len(text)), fillchar)
print(f"{chinese_pad('名字', 10)}{chinese_pad('年龄', 10)}")
问题2:大数字格式化
python复制big_num = 1234567890
print(f"{big_num:,}") # 1,234,567,890
print(f"{big_num:_}") # 1_234_567_890 (Python 3.6+)
print(f"{big_num:.2e}") # 1.23e+09
问题3:动态格式化
python复制# 根据条件动态选择格式
def format_temperature(temp, use_fahrenheit=False):
unit = "°F" if use_fahrenheit else "°C"
value = temp * 9/5 + 32 if use_fahrenheit else temp
return f"{value:.1f}{unit}"
print(format_temperature(25)) # 25.0°C
print(format_temperature(25, True)) # 77.0°F
在实际项目中,我发现很多开发者会忽视输入输出的本地化和国际化问题。比如日期格式、数字格式、货币符号等,不同地区有不同的习惯。建议在项目早期就考虑这些因素,使用Python的locale模块或第三方库如babel来处理国际化需求。
