2.3 字符串
数字讲完了,这一节讲文本。名字、地址、聊天消息、网页内容……程序要处理的信息里,文本占了大头。Python 里的文本类型叫字符串(str),它的操作比数字丰富得多,也是面试和实战的高频考点。内容稍多,我们拆开慢慢讲。
创建字符串:引号的讲究
被引号包住的就是字符串。单引号、双引号完全等价:
a = "你好"
b = 'hello'
那为什么要提供两种?看这个场景——文本内容里本身带引号:
c = "I'm fine" # 内容有单引号(I'm),外面就用双引号包
d = '他说:"加油"' # 内容有双引号,外面就用单引号包
如果内外用了同一种引号,Python 会在中途就认为字符串结束了,直接报 SyntaxError:
e = 'I'm fine' # ❌ SyntaxError:Python 读到 I' 就以为字符串完了
想写多行文本,用三个引号:
poem = """床前明月光,
疑是地上霜。
举头望明月,
低头思故乡。"""
print(poem)
普通引号里直接换行会报错,三引号里可以随意换行,写公告、写长段说明很方便。
💡 本教程统一用双引号,你自己选一种保持统一即可。另外再提醒一次 1.3 节的老坑:必须是英文引号,中文引号
“”会报 SyntaxError。
字符串的加法和乘法
字符串也能用 + 和 *,但含义和数字不同:
first = "Python"
second = "很有趣"
print(first + second) # Python很有趣 + 是拼接:首尾相连
print(first * 3) # PythonPythonPython * 是重复
print("-" * 30) # ------------------------------ 打印分隔线的小技巧
上一节的老朋友 TypeError 在这里最容易出现——字符串只能和字符串相加:
age = 18
print("我今年" + age) # ❌ TypeError:str 不能和 int 相加
print("我今年" + str(age)) # ✅ 先用 str() 转换
不过这种 str() 转来转去的写法很啰嗦,Python 有更优雅的方案,也是本节最重要的知识点——
f-string:把变量嵌进文本(重点!)
在引号前面加一个字母 f,字符串里就可以用 {} 直接放变量:
name = "小明"
age = 18
print(f"我叫{name},今年{age}岁") # 我叫小明,今年18岁
对比一下两种写法:
print("我叫" + name + ",今年" + str(age) + "岁") # + 拼接:碎、要手动转类型
print(f"我叫{name},今年{age}岁") # f-string:像填空一样自然
f-string 的规则:
- 引号前的
f不能少——忘写f是最常见的错误,不报错,但{name}会被原样打印出来:
print("我叫{name}") # 我叫{name} ← 忘了 f,花括号被当成普通文本
print(f"我叫{name}") # 我叫小明 ← 正确
{}里不仅能放变量,还能放任何表达式(运算、函数调用都行):
price = 19.9
print(f"3 件共 {price * 3} 元") # 3 件共 59.699999999999996 元
- 又见浮点数误差!f-string 内置了解决办法:
{值:.2f}表示保留 2 位小数:
print(f"3 件共 {price * 3:.2f} 元") # 3 件共 59.70 元
:.2f 可以拆开记:: 后面是格式说明,.2 是两位小数,f 是按浮点数显示。想保留 1 位就是 :.1f。
从现在起,拼接文本一律优先用 f-string,整套教程后面都会用它。
len():字符串有多长
print(len("Python")) # 6
print(len("你好")) # 2,一个汉字也算 1 个字符
print(len("")) # 0,空字符串(两个引号挨着,里面什么都没有)
len() 和 print()、type() 一样是内置函数,统计密码位数、限制昵称长度都靠它。
索引:取出单个字符
字符串里的每个字符都有编号,叫索引。关键规则:从 0 开始数:
s = " P y t h o n "
索引: 0 1 2 3 4 5
用 字符串[索引] 取出对应字符:
s = "Python"
print(s[0]) # P ← 第 1 个字符的索引是 0!
print(s[1]) # y
print(s[5]) # n
为什么从 0 开始?这是几乎所有编程语言的通用约定(有历史原因),别问为什么,先适应它:第 1 个字符是 [0],第 n 个字符是 [n-1]。
索引还可以是负数,表示从后往前数,-1 是最后一个:
s = " P y t h o n "
正着数: 0 1 2 3 4 5
倒着数:-6 -5 -4 -3 -2 -1
print(s[-1]) # n,最后一个字符(不用先算长度,非常好用)
print(s[-2]) # o,倒数第二个
索引超出范围会报错:
print(s[6]) # ❌ IndexError: string index out of range
IndexError 意思是"编号越界"——"Python" 只有 6 个字符,最大索引是 5。
切片:截取一段
取一个字符用索引,取一段就用切片,语法 s[开始:结束]:
s = "Python"
print(s[0:3]) # Pyt
注意 s[0:3] 取到的是索引 0、1、2 三个字符,不包含索引 3。这条规则叫含头不含尾,是切片唯一需要记牢的规则:
s[0:3] 的范围:
P y t h o n
0 1 2 3
├───取───┤ ↑ 到 3 停止,但不含 3
开始和结束都可以省略:省略开始就是"从头",省略结束就是"到尾":
print(s[2:]) # thon 从索引 2 到末尾
print(s[:4]) # Pyth 从开头到索引 3(不含 4)
print(s[:]) # Python 从头到尾,完整复制一份
print(s[-3:]) # hon 倒数 3 个字符
切片是真正的实战利器。比如从 "20260726" 这种日期字符串里拆出年月日:
date = "20260726"
year = date[:4] # "2026"
month = date[4:6] # "07"
day = date[6:] # "26"
print(f"{year}年{month}月{day}日") # 2026年07月26日
字符串方法:文本自带的工具箱
先认识一个新概念:方法。方法就是"某种数据自带的功能",用点来调用:变量.方法名()。可以理解成:函数是公共工具(len(s) 谁都能用),方法是字符串随身携带的私人工具(s.upper() 只有字符串有)。
最常用的几个:
s = " Hello Python "
print(s.strip()) # "Hello Python" 去掉两端的空格
print(s.upper()) # " HELLO PYTHON " 全部转大写
print(s.lower()) # " hello python " 全部转小写
print(s.replace("Python", "World")) # " Hello World " 把 A 替换成 B
按分隔符把字符串拆成多段(结果是列表,第 4 章会细讲,先眼熟):
s2 = "苹果,香蕉,橘子"
print(s2.split(",")) # ['苹果', '香蕉', '橘子']
判断是否包含某段文本,用 in(结果是 bool):
print("Python" in " Hello Python ") # True
print("Java" in " Hello Python ") # False
实战里它们的典型用途:strip() 清理用户输入两端的空格,lower() 让"YES/yes/Yes"统一成一种再判断,replace() 批量替换敏感词。
大坑:方法不会修改原字符串
这是本节第二重要的知识点。运行这段代码:
s = "hello"
s.upper()
print(s) # hello ??怎么没变成大写?
因为字符串是不可变的——任何方法都不会改动原字符串,而是返回一个修改后的新字符串。原来的 s 从头到尾没变过,s.upper() 产生的新字符串没人接收,直接被丢弃了。
想保留结果,必须用变量接住(通常就是重新赋值给自己):
s = "hello"
s = s.upper() # 用新字符串覆盖旧的
print(s) # HELLO ✅
顺便一提,"不可变"也意味着不能通过索引改字符:
s = "hello"
s[0] = "H" # ❌ TypeError: 'str' object does not support item assignment
想改就整体替换:s = "H" + s[1:] 或用 replace()。
方法返回新字符串还带来一个好处——可以链式调用,前一个方法的结果直接调下一个方法:
s = " Hello Python "
print(s.strip().lower()) # "hello python",先去空格,再转小写
本节报错速查
| 报错 | 人话翻译 | 本节的触发场景 |
|---|---|---|
SyntaxError | 语法错误 | 引号内外同款、引号没配对、用了中文引号 |
TypeError | 类型不对 | 字符串和数字相加;给字符串按索引赋值 |
IndexError | 编号越界 | 索引超过 len(s) - 1 |
练习
新建 practice23.py 完成:
1. 用变量存你的姓名和身高,用 f-string 输出 我叫XX,身高X.XX米(身高保留 2 位小数)。
2. 用切片从字符串 "20260726" 中取出年、月、日并用 f-string 打印。
3. 不运行,先猜输出,再验证:
s = "Python"
print(s[-1] * 3)
print(s[1:4])
print(len(s[2:]))
print("PY" in s.upper())
4. 下面的代码想把用户昵称清理干净(去两端空格、转小写)再打印,但运行后昵称一点没变,找出问题修好它:
nickname = " PyMaster "
nickname.strip()
nickname.lower()
print(f"欢迎你,{nickname}!")
点击查看答案
# 1
name = "小明"
height = 1.75
print(f"我叫{name},身高{height:.2f}米")
# 2
date = "20260726"
print(f"{date[:4]}年{date[4:6]}月{date[6:]}日")
第 3 题:
s[-1] * 3→nnn(最后一个字符是 n,重复 3 次)s[1:4]→yth(索引 1、2、3,含头不含尾)len(s[2:])→4("thon"有 4 个字符)"PY" in s.upper()→True(转大写后是"PYTHON",包含"PY")
第 4 题: 字符串方法不修改原字符串,返回值没有接收,等于白调用。要重新赋值(可以链式):
nickname = " PyMaster "
nickname = nickname.strip().lower()
print(f"欢迎你,{nickname}!") # 欢迎你,pymaster!
本章小结
- 单引号双引号等价,内容带引号时内外错开用;三引号写多行
+拼接、*重复;和数字拼接要先str()——但更好的选择是 f-string- f-string:
f"文本{变量}文本",{}里可运算,:.2f控制小数位;别忘了f - 索引从 0 开始,
-1是最后一个;切片[a:b]含头不含尾 - 方法用
变量.方法名()调用;常用strip/upper/lower/replace/split,in判断包含 - 字符串不可变:方法返回新字符串,要用变量接住
下一节:2.4 输入与输出