f-string 出来之前,Python 字符串格式化到底有多痛苦

如果你是从 Python 3.6 开始学的,你可能不知道以前的人格式化字符串有多折腾。

%s.format()、位置参数、关键字参数……一套组合拳下来,一个简单的字符串拼接能写三行。

好在 f-string 来了。今天把字符串这事一次讲明白。

创建字符串的三种姿势

s1 = 'hello'                    # 单引号
s2 = "world"                    # 双引号,效果一样
s3 = '''第一行
第二行
第三行'''                       # 三引号,可以跨行
s4 = "It's a nice day"          # 字符串里有单引号,用双引号包
s5 = '他说:"你好"'              # 字符串里有双引号,用单引号包

单引号和双引号没区别,纯粹看习惯。我一般用双引号,因为英语里缩写多(it'sdon't),双引号包裹能省转义。

字符串也能"切片"

字符串本质上是字符的序列,所以支持切片操作:

s = "Hello Python"

print(s[0])       # H — 单个字符
print(s[-1])      # n — 倒数第一个
print(s[0:5])     # Hello — 索引 0 到 5(不含5)
print(s[6:])      # Python — 从索引6到最后
print(s[:5])      # Hello — 从头到索引5
print(s[::2])     # HloPto — 每隔一个字符取一个
print(s[::-1])    # nohtyP olleH — 反转字符串!

切片公式:[start:end:step]

  • start:默认 0(开头)
  • end:默认末尾(不包含)
  • step:默认 1

反转字符串用 [::-1] 是 Python 的经典 tricks,面试常考。

常用方法:这些是你天天要用的

s = "  Hello, Python World!  "

# 去空白
print(s.strip())       # "Hello, Python World!"
print(s.lstrip())      # 去左边空白
print(s.rstrip())      # 去右边空白

# 大小写
print(s.upper())       # 全大写
print(s.lower())       # 全小写
print(s.title())       # 每个单词首字母大写

# 查找替换
print(s.find("Python"))   # 8 — 返回索引,找不到返回 -1
print(s.index("Python"))  # 8 — 找不到直接报错
print(s.replace("Python", "Java"))  # 替换
print(s.count("o"))       # 2 — 统计出现次数

# 判断
print(s.startswith("  He"))  # True
print(s.endswith("!"))       # False(末尾有空格)
print("123".isdigit())       # True
print("abc".isalpha())       # True
print("abc123".isalnum())    # True

# 分割与合并
print(s.split())        # ['Hello,', 'Python', 'World!'] — 默认按空白分割
print(s.split(","))     # ['  Hello', ' Python World!  ']

words = ["Hello", "Python", "World"]
print(" ".join(words))  # "Hello Python World" — 用空格连接
print(", ".join(words))  # "Hello, Python, World"

split()join() 是一对,一个拆一个合,数据清洗时出场率极高。

格式化:f-string 一把梭

以前的方式(了解就行,别用了)
name = "张三"
age = 28

# % 格式化(Python 2 时代的遗产)
print("我叫%s,今年%d岁" % (name, age))

# .format() 方法(Python 3 早期)
print("我叫{},今年{}岁".format(name, age))
print("我叫{0},今年{1}岁,{0}是个好人".format(name, age))  # 可以复用
print("我叫{n},今年{a}岁".format(n=name, a=age))           # 关键字
f-string(Python 3.6+,用这个)
name = "张三"
age = 28
height = 1.75

print(f"我叫{name},今年{age}岁")
print(f"明年我就{age + 1}岁了")     # 大括号里可以写表达式
print(f"身高{height:.1f}米")        # 保留1位小数
print(f"姓名:{name:>10}")          # 右对齐,占10个字符宽度
print(f"进度:{0.865:.1%}")         # 百分比格式 → 86.5%

# 多行 f-string
msg = (
    f"姓名:{name}\n"
    f"年龄:{age}\n"
    f"身高:{height}"
)

说实话,f-string 是我最喜欢 Python 3.6 的特性,没有之一。可读性好,性能也比 .format() 快。

编码问题:和乱码说再见

s = "你好"
print(len(s))           # 2 — Python 3 中 len 返回字符数
print(s.encode("utf-8"))  # b'\xe4\xbd\xa0\xe5\xa5\xbd' — 6个字节
print(len(s.encode("utf-8")))  # 6

# 编码解码
text = "中文"
encoded = text.encode("utf-8")   # 字符串 → 字节
decoded = encoded.decode("utf-8") # 字节 → 字符串

Python 3 默认用 UTF-8,基本告别了 Python 2 时代的编码噩梦。但读写文件时还是要注意指定 encoding="utf-8"

转义字符:那些反斜杠的事

print("第一行\n第二行")    # \n 换行
print("列1\t列2\t列3")     # \t 制表符
print("他说:\"你好\"")     # \" 转义引号
print("路径:C:\\Users")   # \\ 转义反斜杠

# 原始字符串:不转义
print(r"C:\Users\new\text")  # 反斜杠保持原样

Windows 路径里的反斜杠和转义符 \n 撞车是常见坑。要么用原始字符串 r"",要么用正斜杠 /,Python 都认。

新手常见坑

坑1:字符串不可变

s = "hello"
# s[0] = "H"  # TypeError! 字符串不能原地修改
s = "H" + s[1:]   # 只能创建新字符串

坑2:is vs ==

a = "hello"
b = "hello"
print(a == b)  # True — 值相等
print(a is b)  # True — 同一个对象(短字符串被 Python 缓存了)

# 但别依赖这个行为
c = "hello world!"
d = "hello world!"
print(c is d)  # 可能是 False!

判断字符串相等永远用 ==,别用 is

坑3:split() 的空字符串陷阱

print("".split())   # [] — 空字符串 split 返回空列表
print(" ".split())  # [] — 纯空格也返回空列表
print("a b".split())  # ['a', 'b'] — 正常

动手试试

  1. 把你的名字反转输出
  2. 统计一段文字中某个字出现的次数
  3. 用 f-string 格式化输出一个简单的个人名片

参考答案:

# 1. 名字反转
name = "张三丰"
print(name[::-1])  # 丰三张

# 2. 统计字数
text = "清明时节雨纷纷,路上行人欲断魂"
char = "人"
print(f"'{char}'出现了{text.count(char)}次")

# 3. 名片
name = "张三"
title = "Python 开发工程师"
email = "zhangsan@example.com"
print(f"""
{'='*30}
  {name:^20}
  {title:^20}
  {email:^20}
{'='*30}
""")

写在最后

字符串看着简单,但它是编程里被操作最多的数据类型。日志、配置文件、用户输入、API 返回——全是字符串。

把切片、split/join、f-string 这三板斧练熟,日常 80% 的字符串操作就够了。

下一篇聊聊元组和集合——两个经常被忽略但关键时刻真香的数据结构。

更多推荐