Python 简单输入输出:input() 与 print()
一、input() 不要信任用户的输入
基础语法
user_input = input("请输入: ") # 返回值永远是字符串(str)
业务实战技巧
1. 防御性类型转换(带验证循环)
生产环境直接转换不安全,需要处理异常:
def get_int(prompt, min_val=None, max_val=None):
"""获取整数输入,带范围验证"""
while True:
try:
value = int(input(prompt))
if min_val is not None and value < min_val:
print(f"值不能小于 {min_val}")
continue
if max_val is not None and value > max_val:
print(f"值不能大于 {max_val}")
continue
return value
except ValueError:
print("请输入有效的数字")
# 使用
age = get_int("请输入年龄: ", min_val=0, max_val=150)
2. 敏感信息输入(密码隐藏)
业务中输入密码不要用 input,会被历史记录:
import getpass
password = getpass.getpass("请输入密码: ") # 输入时不显示字符
3. 多行输入与 EOF 处理
处理配置文件粘贴或管道输入:
print("请输入多行文本,Ctrl+D (Unix) 或 Ctrl+Z (Windows) 结束:")
lines = []
try:
while True:
line = input()
lines.append(line)
except EOFError: # 捕获结束符
pass
content = "\n".join(lines)
4. 输入超时(自动化场景)
在无人值守或自动化脚本中,防止无限等待:
import signal
class TimeoutError(Exception):
pass
def timeout_handler(signum, frame):
raise TimeoutError("输入超时")
# 设置 5 秒超时(Unix/Linux 适用)
signal.signal(signal.SIGALRM, timeout_handler)
signal.alarm(5)
try:
answer = input("请在 5 秒内输入: ")
signal.alarm(0) # 取消超时
except TimeoutError:
print("\n超时,使用默认值")
answer = "default"
5. 历史记录与自动补全(CLI 工具)
对于内部管理后台或命令行工具,提升体验:
import readline # Unix/Linux 下启用输入历史(按上下键)
# 启用后,用户可以使用上下箭头浏览历史输入
name = input("用户名: ")
永远不要 eval(input())
# 危险!用户输入 __import__('os').system('rm -rf /') 就完蛋了
result = eval(input("请输入表达式: ")) # 禁止!
# 安全替代:使用 ast.literal_eval 处理字面量
import ast
data = ast.literal_eval(input("请输入列表: ")) # 只允许常量表达式
二、print() 只做有效输出
基础语法
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
业务实战技巧
1. 实时输出与进度条(flush 参数)
长时间任务中,用户需要看到实时反馈:
import time
for i in range(100):
print(f"\r进度: {i+1}/100 [{('=' * (i+1))}{' ' * (99-i)}]", end="", flush=True)
time.sleep(0.1)
print() # 最后换行
# 关键点:flush=True 强制立即输出,否则会被缓冲区延迟
2. 重定向到日志文件
调试时同时输出到屏幕和文件:
import sys
from datetime import datetime
log_file = open("app.log", "a", encoding="utf-8")
def log(*args, **kwargs):
"""同时打印到控制台和日志文件"""
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
message = " ".join(map(str, args))
print(f"[{timestamp}] {message}", file=sys.stdout) # 屏幕
print(f"[{timestamp}] {message}", file=log_file) # 文件
log_file.flush() # 确保持久化
log("系统启动", "版本 1.0")
3. 结构化表格输出(sep 与格式化)
业务报表的简易展示:
headers = ["ID", "Name", "Score"]
data = [
[1, "Alice", 95],
[2, "Bob", 87],
[3, "Charlie", 92]
]
# 打印表头
print(f"{headers[0]:<5} {headers[1]:<10} {headers[2]:<5}")
print("-" * 25)
for row in data:
print(f"{row[0]:<5} {row[1]:<10} {row[2]:<5}")
4. 日志级别替代方案(小型脚本)
不适合引入 logging 模块的轻量级场景:
import sys
DEBUG = True
def debug_print(*args, **kwargs):
if DEBUG:
print("[DEBUG]", *args, **kwargs)
def error_print(*args, **kwargs):
print("[ERROR]", *args, file=sys.stderr, **kwargs) # 错误输出到 stderr
debug_print("连接数据库...") # 只有 DEBUG=True 才显示
error_print("连接失败!") # 始终显示,且区分输出流
用 logging 替代 print
在真实业务代码(Web 服务、数据处理管道)中,print 是反模式:
# 错误:无法关闭、无法控制级别、无法轮转
print(f"用户 {user_id} 登录成功")
# 正确:可配置、可分级、可输出到 ELK/Splunk
import logging
logger = logging.getLogger(__name__)
logger.info("用户登录成功", extra={"user_id": user_id})
print 仅适用于:
- 命令行工具 (CLI)
- 一次性脚本
- 教学/调试代码
- Jupyter Notebook 探索性分析
核心设计原则
- 所有
input()都经过验证 - 使用
file=sys.stderr区分正常输出和错误 - 提供确认机制、默认值、清晰的提示
- 将 I/O 逻辑与业务逻辑分离,便于单元测试
总结
| 函数 | 关键注意点 |
|---|---|
input() | 永远返回字符串;需要验证类型;敏感信息用 getpass;防止 eval 注入 |
print() | 用 flush=True 实时输出;生产环境用 logging;错误输出到 stderr |
input() 的核心是验证,print() 在生产环境中应替换为 logging。
📌 本文是 python-basics 的专题展开。