Python字符串是文本处理的基础类型。原文从创建方式、不可变性、转义、拼接、编码和性能几个方面做了整理。下面按实际开发中的使用场景重新组织:先看六种创建写法及适用条件,再说明字符串不可变带来的修改方式,最后给出拼接、编码和类型校验中容易踩的坑。
一、六种创建方式与选择建议
1. 单引号和双引号
Python中单引号与双引号完全等价,选择的关键是少写转义。字符串里包含双引号时用单引号;包含单引号时用双引号。项目内保持统一风格即可。
- name = '小明'
- message = 'Hello, Python!'
- text = 'I\'m a Python developer'
- quote = '他说:"Python很有趣!"'
- path = 'D:\\Projects\\Python'
复制代码
2. 三引号
三个单引号或三个双引号可以创建多行字符串,换行会被保留;也常用于函数、类、模块的docstring。用repr()可以看到换行被保存为\n。
- multiline = '''第一行
- 第二行
- 第三行'''
- print(repr(multiline))
- # '第一行\n第二行\n第三行'
- def demo():
- '''函数说明文档'''
- pass
复制代码
3. str()构造函数
str()用于把整数、浮点数、布尔值、None、列表、字典等转换为字符串。自定义类可以实现__str__和__repr__,分别面向用户和开发者。
- print(str(42)) # '42'
- print(str(3.14159)) # '3.14159'
- print(str(True)) # 'True'
- print(str(None)) # 'None'
- class Person:
- def __init__(self, name, age):
- self.name = name
- self.age = age
- def __str__(self):
- return f'{self.name}({self.age}岁)'
- def __repr__(self):
- return f"Person(name='{self.name}', age={self.age})"
- person = Person('小明', 25)
- print(str(person)) # 小明(25岁)
- print(repr(person)) # Person(name='小明', age=25)
复制代码
4. 原始字符串r-string
普通字符串中的反斜杠是转义符,写Windows路径或正则表达式时容易出现双反斜杠。原始字符串在字符串前加r,反斜杠按字面处理。需要注意:原始字符串末尾仍然不能是单个反斜杠,r'hello\'会触发SyntaxError,r'hello\\'才合法。
- path1 = 'C:\\Users\\小明\\Documents'
- path2 = r'C:\Users\小明\Documents'
- print(path1)
- print(path2)
- import re
- pattern = r'\d{3}-\d{4}-\d{4}'
- text = '我的电话是138-1234-5678'
- match = re.search(pattern, text)
- print(match.group() if match else '未匹配')
复制代码
5. f-string
f-string从Python 3.6引入,是当前更推荐的格式化方式。花括号内可以放变量、表达式、条件表达式,也可以调用方法;格式说明符可以控制小数位。Python 3.8+还支持{变量=}调试写法。
- name = '小明'
- age = 25
- score = 95.5
- print(f'我叫{name},今年{age}岁')
- print(f'明年我就{age + 1}岁了')
- print(f'我的分数是{score},等级是{"优秀" if score >= 90 else "良好"}')
- pi = 3.141592653589793
- print(f'π ≈ {pi:.2f}')
- print(f'π ≈ {pi:.4f}')
- name = 'python'
- print(f'{name.upper()}')
- print(f'{name.capitalize()}')
- print(f'{name=} {age=} {score=}')
复制代码
二、不可变性与序列访问
字符串一旦创建就不可修改。对name[1]赋值会抛TypeError;所谓修改,实际上是通过切片和拼接生成新字符串。这个特性让字符串在多个引用之间共享时更安全。
- name = 'Pithon'
- # name[1] = 'y' # TypeError
- name = name[:1] + 'y' + name[2:]
- print(name) # Python
复制代码
字符串是有序字符序列:索引从0开始,支持负索引、切片、遍历和len()。Python 3的str以Unicode存储,中文、日文、阿拉伯文和emoji都可以直接表示。ord()取码点,chr()从码点还原字符。
- text = 'Hello'
- print(text[0]) # H
- print(text[-1]) # o
- print(len(text)) # 5
- for char in text:
- print(char, end=' ')
- print(ord('中')) # 20013
- print(ord('🐍')) # 128013
- print(chr(20013)) # 中
- print(chr(128013)) # 🐍
复制代码
三、转义字符与Unicode写法
常用转义包括\n换行、\t制表、\\反斜杠本身、\'单引号、\"双引号,以及较少使用的\r回车和\b退格。Unicode转义可以用\u加4位十六进制、\U加8位十六进制;八进制\101和十六进制\x41也可以表示字符。
- print('Hello\nWorld')
- print('Hello\tWorld')
- print('Hello\\World')
- print('I\'m learning')
- print('\u4f60\u597d') # 你好
- print('\U0001f40d') # 🐍
- print('\101') # A
- print('\x41') # A
复制代码
这里要区分源码中的反斜杠和实际输出。原始字符串适合路径和正则,但并不能让末尾单个反斜杠合法。
四、拼接、重复与join性能
+用于少量拼接,但字符串和其他类型相加会报TypeError,需要先用str()转换。*可以重复字符串,常用于分隔线和标题装饰。相邻的字符串字面量会自动拼接,但这个规则只对字面量生效,对变量不生效。
- first_name = '张'
- last_name = '三'
- full_name = last_name + first_name
- print(full_name) # 张三
- age = 25
- message = '我今年' + str(age) + '岁'
- print(message)
- print('-' * 40)
- print('你好' * 3)
- message = 'Hello, ' 'World!' ' 你好!'
- print(message)
- a = 'Hello'
- b = 'World'
- result = a + b
- print(result)
复制代码
拼接大量字符串时,优先用join()。原因在于字符串不可变:循环中的+=每次都会创建新对象并拷贝旧内容,而join()只需要分配一次内存。原文用10000个字符串做对比,速度差异可能达到上百倍。实际写法是用列表收集片段,最后统一join。
- import time
- words = ['hello'] * 10000
- start = time.perf_counter()
- result = ''
- for word in words:
- result += word
- elapsed_plus = time.perf_counter() - start
- start = time.perf_counter()
- result = ''.join(words)
- elapsed_join = time.perf_counter() - start
- print(f'+ 拼接耗时:{elapsed_plus:.4f}秒')
- print(f'join 耗时:{elapsed_join:.4f}秒')
- lines = []
- for i in range(1000):
- lines.append(f'第{i}行')
- result = '\n'.join(lines)
复制代码
join也适合URL路径和HTML片段拼接。下面路径示例输出api/v1/users/123;HTML示例用生成器表达式给每个列表项加li标签。
- path_parts = ['api', 'v1', 'users', '123']
- url = '/'.join(path_parts)
- print(url)
- items = ['苹果', '香蕉', '橘子']
- html = '<ul>\n' + '\n'.join(f' <li>{item}</li>' for item in items) + '\n</ul>'
- print(html)
复制代码
五、str与bytes:编码解码和文件读写
str是人类可读的Unicode文本,bytes是机器存储和传输的原始字节。str转bytes用encode(),bytes转str用decode()。编码和解码必须使用一致的编码格式,否则会出现乱码或UnicodeDecodeError。UTF-8最通用;GBK/GB2312常见于中文Windows环境;UTF-16是另一种编码;ASCII只支持英文字符,中文用ASCII编码会抛UnicodeEncodeError。
- text = '你好,Python!'
- encoded = text.encode('utf-8')
- print(encoded)
- print(type(encoded))
- decoded = encoded.decode('utf-8')
- print(decoded)
- print(type(decoded))
- text = '你好,世界!'
- utf8_bytes = text.encode('utf-8')
- gbk_bytes = text.encode('gbk')
- utf16_bytes = text.encode('utf-16')
- print(f'UTF-8: {utf8_bytes}({len(utf8_bytes)}字节)')
- print(f'GBK: {gbk_bytes}({len(gbk_bytes)}字节)')
- print(f'UTF-16: {utf16_bytes}({len(utf16_bytes)}字节)')
- ascii_text = 'Hello World'
- ascii_bytes = ascii_text.encode('ascii')
- print(ascii_bytes)
复制代码
文件操作中最常见的乱码原因之一是读写编码不一致。写文件时指定encoding='utf-8',读文件时使用相同编码。
- with open('output.txt', 'w', encoding='utf-8') as f:
- f.write('中文内容')
- with open('output.txt', 'r', encoding='utf-8') as f:
- content = f.read()
复制代码
六、字符串类型判断与校验示例
str提供了一组is开头的方法,用于判断内容类型:isalpha()全字母、isdigit()全数字、isalnum()字母或数字、isspace()全空白、islower()全小写、isupper()全大写、istitle()标题格式、isdecimal()十进制数字、isnumeric()数字字符、isascii()全ASCII。密码复杂度校验可以组合len()和any()使用。
- print('abc'.isalpha()) # True
- print('123'.isdigit()) # True
- print('abc123'.isalnum()) # True
- print(' '.isspace()) # True
- print('abc'.islower()) # True
- print('ABC'.isupper()) # True
- print('Abc'.istitle()) # True
- print('123'.isdecimal()) # True
- print('123'.isnumeric()) # True
- print('abc'.isascii()) # True
- def validate_password(password):
- if len(password) < 8:
- return False, '密码至少8位'
- if not any(c.isupper() for c in password):
- return False, '密码必须包含大写字母'
- if not any(c.islower() for c in password):
- return False, '密码必须包含小写字母'
- if not any(c.isdigit() for c in password):
- return False, '密码必须包含数字'
- return True, '密码符合要求'
- print(validate_password('abc'))
- print(validate_password('abcdefgh'))
- print(validate_password('Abcdefgh1'))
复制代码
七、实践选择清单
需要多行文本或文档字符串时用三引号;路径和正则优先用r-string,但末尾不能是单个反斜杠;需要格式化输出时用f-string,Python 3.6+可用,调试写法需要3.8+;需要把其他类型转成字符串时用str(),自定义类同时实现__str__和__repr__;少量拼接可用+,大量拼接用列表收集后join();处理文件、网络和数据库文本时明确编码,读写两端保持一致;密码或格式校验可组合is系列方法和any()。这些选择都围绕原文示例中的事实:字符串不可变、转义规则、编码差异和join的分配方式。 |