跳到主要内容

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] * 3nnn(最后一个字符是 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 / splitin 判断包含
  • 字符串不可变:方法返回新字符串,要用变量接住

下一节:2.4 输入与输出