Python I/O 与字符串格式化:那些容易被忽略的关键细节

2026-05-26 21 预计阅读时间:1 分钟
来源:realpython.com AI 摘要 原文链接

免责声明:本文为 AI 摘要整理,建议结合原文阅读。摘要可能省略上下文、版本差异或边界条件,不作为官方说明。

预计阅读时间:8 分钟

input()print()strip()format()、f-string——这些是每个 Python 初学者最早接触的函数,但恰恰因为"太基础",不少开发者用了很多年依然会在细节上踩坑。比如 strip() 到底删什么字符?format mini-language 里的 ,.2f 有什么区别?f-string 里能不能调用函数?这篇文章把这些点逐一拆开,配上可运行的代码,帮你把基础真正夯实。

input() 和 print() 的隐藏行为

input() 总是返回字符串,不管用户敲的是数字还是路径。这是最常被遗忘的一点:

age = input("请输入年龄:")
# 用户输入 25,age 是 "25",不是 25
# 直接做算术会报 TypeError
# age + 1  → TypeError: can only concatenate str to str
age_int = int(age)  # 必须显式转换

print()sepend 参数经常被忽略,但它们在日志和格式化输出中非常实用:

# 用逗号分隔多个值,末尾不加换行
print("user_id", "login", "success", sep=",", end=";\n")
# 输出: user_id,login,success;

print() 还支持 file 参数,可以直接写入文件对象,省去 write() + 换行拼接:

with open("log.txt", "a") as f:
    print("2024-01-15 task done", file=f)

strip 家族:不只是去空格

strip()lstrip()rstrip() 删除的并不是"空格",而是所有位于边缘的指定字符。默认字符集包括空格、\t\n\r\x0b\x0c。你可以传入自定义字符:

path = "/usr/local/bin/"
path.rstrip("/")   # '/usr/local/bin'  — 去掉尾部斜杠

raw = ">>> hello <<<"
raw.strip(">< ")   # 'hello'  — 同时去掉 > < 和空格

# 注意:strip 是两端同时删,不是只删一头
"  mid  ".strip()  # 'mid'

一个常见误用:想删固定前缀时用 strip,但它会删所有匹配字符,直到遇到不匹配的为止:

filename = "___config.yaml"
filename.strip("_")  # 'config.yaml' — 意料之中

filename = "__init__.py"
filename.strip("_")  # 'init.py' — 如果只想删前缀,应该用 lstrip 或 removeprefix
filename.removeprefix("__")  # 'init__.py' — Python 3.9+,精确删前缀

format mini-language:一个被低估的微型 DSL

str.format() 的格式说明符 {:spec} 内部有一套完整的 mini-language,远不止 .2f。几个实用组合:

# 千分位逗号 + 两位小数
revenue = 1234567.891
print("{:,.2f}".format(revenue))  # 1,234,567.89

# 居中对齐,宽度 20,填充字符 ~
title = "REPORT"
print("{:~^20}".format(title))    # ~~~~~~~REPORT~~~~~~~

# 百分比显示
ratio = 0.834
print("{:.1%}".format(ratio))     # 83.4%

# 二进制 / 八进制 / 十六进制
num = 255
print("{:b}".format(num))   # 11111111
print("{:o}".format(num))   # 377
print("{:#x}".format(num))  # 0xff  — # 加前缀

mini-language 的语法是 [fill][align][sign][#][0][width][grouping_option][.precision][type],可以自由组合。理解了这个结构,你就不需要每次都去查文档了。

f-string:现代 Python 的首选方式

f-string 从 Python 3.6 引入,在可读性和性能上都优于 % 格式化和 str.format()。它支持表达式、函数调用、调试语法(3.8+):

name = "Ada"
score = 97.5

# 基本用法
msg = f"{name} scored {score:.1f}"  # 'Ada scored 97.5'

# 调用函数
def upper(s):
    return s.upper()
print(f"{upper(name)}")  # 'ADA'

# 调试语法 (Python 3.8+)
print(f"{name=}, {score=}")  # name='Ada', score=97.5

# 多行 f-string
report = (
    f"Name: {name}\n"
    f"Score: {score:.1f}\n"
    f"Status: {'pass' if score >= 60 else 'fail'}"
)
print(report)

f-string 里不能用反斜杠(\n 等),但你可以提前把换行符存到变量里再引用。嵌套大括号可以控制格式精度:

width = 10
precision = 2
value = 3.14159
print(f"{value:{width}.{precision}f}")  # '      3.14'

实战:一个迷你命令行日志格式化工具

把上面所有知识点串起来,写一个可以直接跑的小脚本——从用户输入读取日志条目,清洗、格式化后输出到终端和文件:

#!/usr/bin/env python3
"""mini_log_formatter.py — 演示 input/print/strip/format/f-string 综合用法"""

import datetime

def clean_tag(raw: str) -> str:
    """去掉前后空白和特殊符号,保留核心标签"""
    return raw.strip().strip("><").lower()

def format_entry(timestamp, tag, message, width=12):
    """用 f-string + mini-language 格式化单条日志"""
    return f"[{timestamp}] {tag:~<{width}} | {message}"

def main():
    print("=== 日志格式化工具 ===", end="\n\n")

    # input() 总返回 str,需要自行清洗
    raw_tag = input("输入标签(如 >>> ERROR <<<):")
    tag = clean_tag(raw_tag)

    raw_msg = input("输入日志内容:")
    msg = raw_msg.strip()  # 只去空白,不去其他字符

    timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")

    entry = format_entry(timestamp, tag, msg)

    # 终端输出,用 sep 简化
    print(entry)

    # 同时写入文件,用 print 的 file 参数
    with open("mini_log.txt", "a") as f:
        print(entry, file=f)

    # 用 format mini-language 做统计摘要
    print("\n--- 统计 ---")
    print(f"标签长度: {len(tag)}")
    print(f"原始输入: {raw_tag!r}")  # !r 显示 repr
    print("{:^30}".format("END OF ENTRY"))

if __name__ == "__main__":
    main()

运行方式:

python3 mini_log_formatter.py
# 交互输入后,终端和 mini_log.txt 都会收到格式化日志

选用建议与易错清单

场景 推荐方式 原因
日常字符串拼接 f-string 可读性最好,性能最高
需要动态格式参数 str.format() f-string 嵌套大括号可读性差
旧代码 / 日志库 % 格式化 兼容性,但新项目不建议
删固定前缀/后缀 removeprefix/removesuffix (3.9+) 精确,不会误删
删边缘任意字符 strip/lstrip/rstrip 灵活,但要留意"删到不匹配为止"的行为

几个高频踩坑点,值得加到团队 checklist:

  1. input() 返回 str——做数值运算前必须 int() / float()
  2. strip() 不是 trim()——它删字符集,不是只删空格;删前缀优先用 removeprefix
  3. f-string 里不能写 \n——提前赋值给变量再引用。
  4. !r!s 调整显示方式——f"{value!r}" 输出 repr,调试时很有用。
  5. print(end=..., sep=..., file=...)——三个参数能省掉不少手动拼接。

把这些细节吃透,"基础"才不会成为隐患。


相关推荐