字符串
将所有行限制在最多79个字符。对于文档字符串或注释等流动的长文本块,行长度应限制在72个字符。
愚蠢的一致性是小心眼的产物。风格指南的建议有时并不适用。当有疑问时,运用你的最佳判断。看看其他例子,决定什么看起来最好。不要犹豫,去问吧!
字符串
直接使用引号定义字符串是最常见的方式,定义字符串可以使用单引号、双引号、三重引号。可以在不同类型的引号内部包含其他引号。
当字符串内包含引号时,需要用不同的引号包裹或转义字符。
print("Hello, world!") # 双引号
print('Hello, world!') # 单引号
print("""Hello, world!""") # 三重引号
print('''Hello, world!''') # 三重引号
# 当你想要定义一个包含单引号的字符串时,可以用双引号包裹
print("It's a nice day!") # It's a nice day!
# 反之,当字符串包含双引号时,可以用单引号包裹
print('He said, "Hello!"') # He said, "Hello!"
# 对于多行字符串,三引号允许内部包含单双引号
print("""He said, "It's a nice day!" """) # He said, "It's a nice day!"
# 对于三引号字符串,和上面的包裹案例,也可以使用转义字符来定义
print("""We can use \"\"\" to define string """) # We can use """ to define string
print("He said, \"It's a nice day!\"") # He said, "It's a nice day!"
print("He said, \"Hello!\"") # He said, "Hello!"
print("It\'s a nice day!") # It's a nice day!
# 连续定义多个字符串(中 间有无空格均可)触发字符串字面值合并
string = "1""2" '3'
print(string)
# 输出:
# 123
字符串属于不可变序列对象。
不可变的,这意味着每次修改都会创建新字符串。
序列对象,表示拥有一些共性方法:
- 加法拼接,返回新的字符串
- 索引,返回单个字符
- 切片,返回新的字符串
- 可遍历,每次返回单个字符
- 可使用in判断是否包含
- 可使用len函数获取长度
s = 'good morning'
# 字符串的索引
s[0] # g
s[-2] # n
# 字符串的切片
s[-3:] # ing
s[:-3] # good morn
s[:] # good morning
# 字符串的拼接
s[:-3] + s[-3:] # good morning
# 遍历
for i in s:
print(i,end=' ')
# 输出:
# g o o d m o r n i n g
# in判断
'a' in 'abc' # True
'z' in 'abc' # False
# 使用len函数获取长 度
len(s) # 13
# 需要注意避免在循环中使用 `+` 操作符(每次拼接都会创建新字符串)
# 推荐使用列表收集,最后使用`str.join()` 连接字符串。
# 低效方式
s = ""
for i in range(10000):
s += str(i) # 创建新字符串每次迭代
# 高效方式
parts = []
for i in range(10000):
parts.append(str(i))
s = "".join(parts)
# 进阶方式,流式写入
import io
s = io.StringIO()
for i in range(10000):
s.write(str(i))
s = s.getvalue()
str函数
str() 函数用于将其他类型的数据转换为字符串类型。这在需要将数字、列表或其他对象作为字符串处理时非常有用。
str函数签名:str(object='') -> str
参数说明:
object
:要转换的对象,默认为空字符串
返回值:
- 返回一个字符串
# 将整数转换为字符串
num = 123
str_num = str(num)
print(str_num) # 输出: '123'
print(type(str_num)) # 输出: <class 'str'>
# 将列表转换为字符串
lst = [1, 2, 3]
str_lst = str(lst)
print(str_lst) # 输出: '[1, 2, 3]'
# 将浮点数转换为字符串
float_num = 3.14
str_float = str(float_num)
print(str_float) # 输出: '3.14'
str() 函数会调用对象的 __str__()
方法来生成字符串表示形式。对于自定义类,可以重写 __str__()
来控制转换结果。
字符串插值
f-string提供了一种简洁、可读性强的字符串格式化方法。
它在运行时计算表达式,比传统的%
格式化和str.format()
更快、更直观。
而且支持调试表达式、函数调用。
name = "world"
print(f"Hello, {name}!") # Hello, world!
# 嵌入表达式
x = 10
y = 20
result = f"{x} add {y} is {x + y}"
print(result) # 输出: 10 add 20 is 30
# 支持函数、属性、方法的调用
name="jack"
info = f"{name}'s name first letter is {name[0].upper()} , the name length is {len(name)}"
print(info) # 输出: jack's name first letter is J , the name length is 4
模板字符串为开发者提供了在字符串组合前访问字符串及其插值值的能力。这为 Python 语言带来了原生的灵活字符串处理功能,并支持安全检查、Web 模板、特定领域语言等。
预计Python 3.14 支持模板字符串。
name = "World"
template = t"Hello {name}"
assert template.interpolations[0].value == "World"
格式说明符
在 str.format() 和 f-strings 中,可以使用格式说明符来控制输出的格式。这对于数字、日期和字符串的精确格式化非常实用。
数字格式化
# 使用 f-strings时,可以直接将值写入,但是推荐先定义变量,代码可读性更好
# 保留两位整数,不足时左侧补零
print(f"{5:02d}") # 输出: 05
# 推荐写法:
value = 5
print(f"{value:02d}")
# 保留两位小数,不足末位补0
pi = 3.14159
print(f"{pi:.2f}") # 输出: 3.14
# 调试表达式,等价于print(f"var={var}")
var = 42
print(f"{var=}") # 输出: var=42
# 对于数字,用逗号或下划线作为组分隔符
data = 123456789
print(f'{data:,}') # 123,456,789
print(f'{data:_}') # 123_456_789
# 表示为百分数,保留两位小数
points = 19
total = 22
print(f'{points/total:.2%}') # 86.36%
# 等价于
print(f'{0.8636363636363636:.2%}') # 86.36%
# 对于数字,格式也支持转化为其他进制
num = 42
print(f"int: {num:d}; hex: {num:x}; oct: {num:o}; bin: {num:b}")
# 输出:int: 42; hex: 2a; oct: 52; bin: 101010
print(f"int: {num:d}; hex: {num:#x}; oct: {num:#o}; bin: {num:#b}")
# 输 出:int: 42; hex: 0x2a; oct: 0o52; bin: 0b101010
# 总是显示符号
print(f'{3.14:+f}; {-3.14:+f}')
# 输出:+3.140000; -3.140000
# 对正数显示一个空格
print(f'{3.14: f}; {-3.14: f}')
# 输出: 3.140000; -3.140000
# 只显示负号 -- 等同于 '{:f}; {:f}'
print(f'{3.14:-f}; {-3.14:-f}')
# 输出:3.140000; -3.140000
文本对齐
# 为了便于观察,我在末尾添加了竖线|
hello = "hello|"
name = "bob|"
# 右对齐,表示字符串长度为10,不足时用空格填充
print("{:>10}".format(hello))
print("{:>10}".format(name))
# 输出:
# hello|
# bob|
# 居中对齐,表示字符串长度为10,不足时用空格填充
print("{:^10}".format(hello))
print("{:^10}".format(name))
# 输出:
# hello|
# bob|
# 居左对齐(默认),表示字符串长度为10,不足时用空格填充
print("{:<10}".format(hello))
print("{:<10}".format(name))
# 输出:
# hello|
# bob|
# 左右对齐
class Datebase:
url = '127.0.0.1'
password = '123456'
print(f"""
{"test url:":<20}{Datebase.url:>20}
{"test password:":<20}{Datebase.password:>20}
""")
# 输出:
# test url: 127.0.0.1
# test password: 123456
#
# 带有填充的对齐
# text表示文本,第一处align表示填充字符,第二处align表示对齐方式,16表示长度
for align, text in zip('<^>', ['left', 'center', 'right']):
print(f'{text:{align}{align}16}')
# 输出:
# left<<<<<<<<<<<<
# ^^^^^^center^^^^^
# >>>>>>>>>>right
使用特定类型的专属格式化
import datetime
d = datetime.datetime(2008, 12, 3, 12, 15, 58)
print('{:%Y-%m-%d %H:%M:%S}'.format(d)) # 2008-12-03 12:15:58
# # 2008-12-03 是Python3.0.0的发布日期。
Unicode 和转义字符
Python3 的字符就是Unicode
字符。
Unicode 字符串类型已更改为支持多种内部表示,具体取决于字符的最大 Unicode 序数(1、2 或 4 字节)。这将允许在常见情况下使用空间高效的表示,但在所有系统上都能访问完整的 UCS-4。
Unicode
- bytes: Python 中的字节串类型,用于表示二进制数据。
- ASCII: 最古老的编码标准,只包含128个字符。
- Unicode: 一种字符编码标准,为世界上大多数字符分配唯一的代码点。
- UTF-8: 全称 Unicode Transformation Format 8,向后兼容 ASCII?。是最常见的 Unicode 编码形式,UTF-8是 变长编码,1-4字节表示一个Unicode码点。
- 码表: 字符与编码的映射表,表头包含显示字符、编码值、描述。
下面的示例中,我刻意避免使用字符,为了不让你误解字符串的定义。
# 直接定义,表示Unicode的明文
s = "Hello, 世界!"
print(s) # 输出: Hello, 世界!
# 如果你的电脑无法安装任何输入法,那么你只能使用Unicode码点来表示非英文字符。
# 间接定义,表示Unicode码表的第4e16个文字和第754c个文字,小u后面接4位16进制的数字,即支持16-bit
u = 'Hello, \u4e16\u754c!'
print(u) # 输出: Hello, 世界!
# 如果你要表示的文字在码表中相当靠后,则可以使用大U定义,大U后面接8位16进制的数字,即支持32-bit
U = 'Hello, \U00004e16\U0000754c!'
print(U) # 输出: Hello, 世界!
# 单纯依靠十六进制码点来表示字符好比网站访问靠IP 地址,非常不便。因此Unicode提供了名称来表示字符,就和网站域名一样。
# 你更愿意访问http://142.251.42.100:443/ 还是 https://www.baidu.com/ 呢?
# Unicode 名称此时此刻相当于某种助记符,比如雪人、欧元符号。
print('\N{SNOWMAN}\N{EURO SIGN}')
# 输出:☃€
# 编码为 bytes
b = s.encode('utf-8')
print(b) # 输出: b'Hello, \xe4\xb8\x96\xe7\x95\x8c!'
# 解码回字符串
decoded = b.decode('utf-8')
print(decoded) # 输出: Hello, 世界!
# 处理编码错误
try:
b.decode('ascii')
except UnicodeDecodeError as e:
print(f"Error: {e}") # 输出: Error: 'ascii' codec can't decode byte ...
查询字符的名称可以使用unicodedata
模块。但是注意,\N后面的内容不支持拼接显示。
import unicodedata
# 查询字符 '世界' 的 Unicode 名称(Unicode 名称是字符的官方名称,相当于字符的身份证号)
# 解读一下输出结果你就会发现,汉字的命名规则是:CJK UNIFIED IDEOGRAPH-XXXX,其中XXXX是字符的编码值。
print(unicodedata.name('世'),unicodedata.name('界'))
# 输出:CJK UNIFIED IDEOGRAPH-4E16 CJK UNIFIED IDEOGRAPH-754C
print('\N{CJK UNIFIED IDEOGRAPH-4E16}\N{CJK UNIFIED IDEOGRAPH-754C}')
# 输出:世界
# 会报错:因为\N不支持拼接显示,包含字面值合并、加法拼接、变量传递等
name = 'CJK UNIFIED IDEOGRAPH-4E16'
print(f'\N{name}')
转义字符
转义字符是一种在编程语言和标记语言中使用的特殊字符序列,它是一种语法层面的约定。官方翻译为转义序列。
比如你的键盘没有Tab键,那么你可以输入\t
来表示Tab。
转义字符也是字符串的一部分,因此也属于Unicode
字符。
部分转义字符直接对应ASCII码表中的字符?。
如果响铃符号在Vscode中不触发,可以试试在终端中体验。
下面写法是等价的。都代表 ASCII 码值为 7 的字符。
\a
表示 ASCII 响铃字符的助记符(mnemonic escape sequence)。
它旨在让代码更具可读性,让人一眼就知道这个转义序列的意图是发出响铃。
print('\a') # 助记符
print('\x07') # 16进制
print('\7') # 8进制
print('\07') # 8进制
print('\007') # 8进制
print("\u0007") # Unicode 16进制
print("\U00000007") # Unicode 16进制
print('\N{BEL}') # 直接使用Unicode名称
与数字定义进制相比,字符串转义序列仅支持8进制、16进制,转义后指向码表中的字符。
8进制定义需要以\
开头,不超过三位。最大值为\377
。
16进制定义时,需要以\x
开头,不超过两位。最大值为\xff
。
转义 字符往往以反斜杠\
开头,下面的示例展示了转义字符、反转义字符的用法。
path_str = r'"c:\desktop\new"'
path = r'c:\desktop\new'
literal_bs = r"ABC\bD"
literal_ff = r"第一页内容\f第二页内容"
literal_nl = r"这一行\n下一行"
literal_cr = r"ABC\rD"
literal_tab = r"列1\t列2\t列3"
literal_vt = r"上\v下"
newline = r"PEP8 中推荐每行不超过79个字符,如果一个字符串过长,\
可以使用\换行。"
letter = f"""
亲爱的读者:
\t你好!这是一封用常见转义字符排版并介绍它们的信。
\t1) \\t ASCII 水平制表符(TAB)
\t 文本写法: "{literal_tab}"
\t 输出效果: 列1\t列2\t列3
\t2) \\n ASCII 换行符(LF)
\t 文本写法: "{literal_nl}"
\t 输出效果: 这一行
\t 下一行
\t3) \\f ASCII 换页符(FF)和\\v ASCII 垂直制表符(VT)
\t 文本写法: "{literal_ff}" 和"{literal_vt}"
\t 输出效果: 最早用于打印机换页和垂直定位,目前已经很少使用了,在一些终端/编辑器中表现和换行符一致。
\t4) \\r ASCII 回车符(CR)和 \\b ASCII 退格符(BS)
\t 文本写法: "{literal_cr}" 和 "{literal_bs}"
\t 输出效果: \\r将光标移到当前行的最开始,因此"ABC\\rD" 实际显示常为 "DBC"
\t 输出效果: \\b将光标移到当前行的前一个字符的位置,因此"ABC\\bD" 实际显示常为 "ABD"
\t5) \\<newline>表示斜杠后面接新的一行,会忽略换行。可用于长字符串的定义。
\t 文本写法: "{newline}"
\t 输出效果: PEP8 中推荐每行不超过79个字符,如果一个字符串过长,可以使用\换行。
\t6) 转义字符有时会添乱。\\ + \\ 表示一个反斜杠且不触发转义。但是长文本下我更推荐r来定义原始字符串。
\t 原始字符:{path_str}
\t 输出效果:c:\\desktop\new
\t 改进写法1:"c:\\\\desktop\\\\new" # 输出:{path}
\t 改进写法2:r"c:\\desktop\\new" # 输出:{path}
此致\n\t敬礼!
"""
print(letter)
# 输出:
"""
亲爱的读者:
你好!这是一封用常见转义字符排版并介绍它们的信。
1) \t ASCII 水平制表符(TAB)
文本写法: "列1\t列2\t列3"
输出效果: 列1 列2 列3
2) \n ASCII 换行符(LF)
文本写法: "这一行\n下一行"
输出效果: 这一行
下一行
3) \f ASCII 换页符(FF)和\v ASCII 垂直制表符(VT)
文本写法: "第一页内容\f第二页内容" 和"上\v下"
输出效果: 最早用于打印机换页和垂直定位,目前已经很少使用了,在一些终端/编辑器中表现和换行符一致。
4) \r ASCII 回车符(CR)和 \b ASCII 退格符(BS)
文本写法: "ABC\rD" 和 "ABC\bD"
输出效果: \r将光标移到当前行的最开始,因此"ABC\rD" 实际显示常为 "DBC"
输出效果: \b将光标移到当前行的前一个字符的位置,因此"ABC\bD" 实际显示常为 "ABD"
5) \<newline>表示斜杠后面接新的一行,会忽略换行。可用于长字符串的定义。
文本写法: "PEP8 中推荐每行不超过79个字符,如果一个字符串过长,\
可以使用\换行。"
输出效果: PEP8 中推荐每行不超过79个字符,如果一个字符串过长,可以使用\换行。
6) 转义字符有时会添乱。\ + \ 表示一个反斜杠且不触发转义。但是长文本下我更推荐r来定义原始字符串。
原始字符:"c:\desktop\new"
输出效果:c:\desktop
ew
改进写法1:"c:\\desktop\\new" # 输出:c:\desktop\new
改进写法2:r"c:\desktop\new" # 输出:c:\desktop\new
此致
敬礼!
"""
字符串附加方法
Python中字符串类型的附加方法相当多。你可以根据自己的节奏选择学习。
内置函数
ord函数、chr函数
ord() 函数和 chr() 函数是Python中用于处理字符串和Unicode字符的函数。
ord函数签名:ord(character) -> int
参数说明:
character
:要转换的字符
返回值:
- 返回字符的Unicode码值
chr函数签名:chr(integer) -> str
参数说明:
integer
:要转换的整数
返回值:
- 返回整数对应的字符
print(ord('A')) # 65
print(chr(65)) # A
print(ord('Z')) # 90
print(chr(90)) # Z
for _ in range(ord('A'), ord('Z')+1):
print(chr(_),end=' ')
# 输出:A B C D E F G H I J K L M N O P Q R S T U V W X Y Z