查看: 220|回复: 0

Python字符串创建与拼接实战:六种写法、编码与性能避坑

[复制链接]
发表于 1 小时前 | 显示全部楼层 |阅读模式
Python字符串是文本处理的基础类型。原文从创建方式、不可变性、转义、拼接、编码和性能几个方面做了整理。下面按实际开发中的使用场景重新组织:先看六种创建写法及适用条件,再说明字符串不可变带来的修改方式,最后给出拼接、编码和类型校验中容易踩的坑。

一、六种创建方式与选择建议

1. 单引号和双引号
Python中单引号与双引号完全等价,选择的关键是少写转义。字符串里包含双引号时用单引号;包含单引号时用双引号。项目内保持统一风格即可。
  1. name = '小明'
  2. message = 'Hello, Python!'
  3. text = 'I\'m a Python developer'
  4. quote = '他说:"Python很有趣!"'
  5. path = 'D:\\Projects\\Python'
复制代码

2. 三引号
三个单引号或三个双引号可以创建多行字符串,换行会被保留;也常用于函数、类、模块的docstring。用repr()可以看到换行被保存为\n。
  1. multiline = '''第一行
  2. 第二行
  3. 第三行'''
  4. print(repr(multiline))
  5. # '第一行\n第二行\n第三行'
  6. def demo():
  7.     '''函数说明文档'''
  8.     pass
复制代码

3. str()构造函数
str()用于把整数、浮点数、布尔值、None、列表、字典等转换为字符串。自定义类可以实现__str__和__repr__,分别面向用户和开发者。
  1. print(str(42))        # '42'
  2. print(str(3.14159))   # '3.14159'
  3. print(str(True))      # 'True'
  4. print(str(None))      # 'None'
  5. class Person:
  6.     def __init__(self, name, age):
  7.         self.name = name
  8.         self.age = age
  9.     def __str__(self):
  10.         return f'{self.name}({self.age}岁)'
  11.     def __repr__(self):
  12.         return f"Person(name='{self.name}', age={self.age})"
  13. person = Person('小明', 25)
  14. print(str(person))   # 小明(25岁)
  15. print(repr(person))  # Person(name='小明', age=25)
复制代码

4. 原始字符串r-string
普通字符串中的反斜杠是转义符,写Windows路径或正则表达式时容易出现双反斜杠。原始字符串在字符串前加r,反斜杠按字面处理。需要注意:原始字符串末尾仍然不能是单个反斜杠,r'hello\'会触发SyntaxError,r'hello\\'才合法。
  1. path1 = 'C:\\Users\\小明\\Documents'
  2. path2 = r'C:\Users\小明\Documents'
  3. print(path1)
  4. print(path2)
  5. import re
  6. pattern = r'\d{3}-\d{4}-\d{4}'
  7. text = '我的电话是138-1234-5678'
  8. match = re.search(pattern, text)
  9. print(match.group() if match else '未匹配')
复制代码

5. f-string
f-string从Python 3.6引入,是当前更推荐的格式化方式。花括号内可以放变量、表达式、条件表达式,也可以调用方法;格式说明符可以控制小数位。Python 3.8+还支持{变量=}调试写法。
  1. name = '小明'
  2. age = 25
  3. score = 95.5
  4. print(f'我叫{name},今年{age}岁')
  5. print(f'明年我就{age + 1}岁了')
  6. print(f'我的分数是{score},等级是{"优秀" if score >= 90 else "良好"}')
  7. pi = 3.141592653589793
  8. print(f'π ≈ {pi:.2f}')
  9. print(f'π ≈ {pi:.4f}')
  10. name = 'python'
  11. print(f'{name.upper()}')
  12. print(f'{name.capitalize()}')
  13. print(f'{name=} {age=} {score=}')
复制代码

二、不可变性与序列访问

字符串一旦创建就不可修改。对name[1]赋值会抛TypeError;所谓修改,实际上是通过切片和拼接生成新字符串。这个特性让字符串在多个引用之间共享时更安全。
  1. name = 'Pithon'
  2. # name[1] = 'y'  # TypeError
  3. name = name[:1] + 'y' + name[2:]
  4. print(name)  # Python
复制代码

字符串是有序字符序列:索引从0开始,支持负索引、切片、遍历和len()。Python 3的str以Unicode存储,中文、日文、阿拉伯文和emoji都可以直接表示。ord()取码点,chr()从码点还原字符。
  1. text = 'Hello'
  2. print(text[0])   # H
  3. print(text[-1])  # o
  4. print(len(text)) # 5
  5. for char in text:
  6.     print(char, end=' ')
  7. print(ord('中'))   # 20013
  8. print(ord('🐍'))   # 128013
  9. print(chr(20013))  # 中
  10. print(chr(128013)) # 🐍
复制代码

三、转义字符与Unicode写法

常用转义包括\n换行、\t制表、\\反斜杠本身、\'单引号、\"双引号,以及较少使用的\r回车和\b退格。Unicode转义可以用\u加4位十六进制、\U加8位十六进制;八进制\101和十六进制\x41也可以表示字符。
  1. print('Hello\nWorld')
  2. print('Hello\tWorld')
  3. print('Hello\\World')
  4. print('I\'m learning')
  5. print('\u4f60\u597d')     # 你好
  6. print('\U0001f40d')        # 🐍
  7. print('\101')              # A
  8. print('\x41')              # A
复制代码

这里要区分源码中的反斜杠和实际输出。原始字符串适合路径和正则,但并不能让末尾单个反斜杠合法。

四、拼接、重复与join性能

+用于少量拼接,但字符串和其他类型相加会报TypeError,需要先用str()转换。*可以重复字符串,常用于分隔线和标题装饰。相邻的字符串字面量会自动拼接,但这个规则只对字面量生效,对变量不生效。
  1. first_name = '张'
  2. last_name = '三'
  3. full_name = last_name + first_name
  4. print(full_name)  # 张三
  5. age = 25
  6. message = '我今年' + str(age) + '岁'
  7. print(message)
  8. print('-' * 40)
  9. print('你好' * 3)
  10. message = 'Hello, ' 'World!' ' 你好!'
  11. print(message)
  12. a = 'Hello'
  13. b = 'World'
  14. result = a + b
  15. print(result)
复制代码

拼接大量字符串时,优先用join()。原因在于字符串不可变:循环中的+=每次都会创建新对象并拷贝旧内容,而join()只需要分配一次内存。原文用10000个字符串做对比,速度差异可能达到上百倍。实际写法是用列表收集片段,最后统一join。
  1. import time
  2. words = ['hello'] * 10000
  3. start = time.perf_counter()
  4. result = ''
  5. for word in words:
  6.     result += word
  7. elapsed_plus = time.perf_counter() - start
  8. start = time.perf_counter()
  9. result = ''.join(words)
  10. elapsed_join = time.perf_counter() - start
  11. print(f'+ 拼接耗时:{elapsed_plus:.4f}秒')
  12. print(f'join 耗时:{elapsed_join:.4f}秒')
  13. lines = []
  14. for i in range(1000):
  15.     lines.append(f'第{i}行')
  16. result = '\n'.join(lines)
复制代码

join也适合URL路径和HTML片段拼接。下面路径示例输出api/v1/users/123;HTML示例用生成器表达式给每个列表项加li标签。
  1. path_parts = ['api', 'v1', 'users', '123']
  2. url = '/'.join(path_parts)
  3. print(url)
  4. items = ['苹果', '香蕉', '橘子']
  5. html = '<ul>\n' + '\n'.join(f'  <li>{item}</li>' for item in items) + '\n</ul>'
  6. print(html)
复制代码

五、str与bytes:编码解码和文件读写

str是人类可读的Unicode文本,bytes是机器存储和传输的原始字节。str转bytes用encode(),bytes转str用decode()。编码和解码必须使用一致的编码格式,否则会出现乱码或UnicodeDecodeError。UTF-8最通用;GBK/GB2312常见于中文Windows环境;UTF-16是另一种编码;ASCII只支持英文字符,中文用ASCII编码会抛UnicodeEncodeError。
  1. text = '你好,Python!'
  2. encoded = text.encode('utf-8')
  3. print(encoded)
  4. print(type(encoded))
  5. decoded = encoded.decode('utf-8')
  6. print(decoded)
  7. print(type(decoded))
  8. text = '你好,世界!'
  9. utf8_bytes = text.encode('utf-8')
  10. gbk_bytes = text.encode('gbk')
  11. utf16_bytes = text.encode('utf-16')
  12. print(f'UTF-8: {utf8_bytes}({len(utf8_bytes)}字节)')
  13. print(f'GBK: {gbk_bytes}({len(gbk_bytes)}字节)')
  14. print(f'UTF-16: {utf16_bytes}({len(utf16_bytes)}字节)')
  15. ascii_text = 'Hello World'
  16. ascii_bytes = ascii_text.encode('ascii')
  17. print(ascii_bytes)
复制代码

文件操作中最常见的乱码原因之一是读写编码不一致。写文件时指定encoding='utf-8',读文件时使用相同编码。
  1. with open('output.txt', 'w', encoding='utf-8') as f:
  2.     f.write('中文内容')
  3. with open('output.txt', 'r', encoding='utf-8') as f:
  4.     content = f.read()
复制代码

六、字符串类型判断与校验示例

str提供了一组is开头的方法,用于判断内容类型:isalpha()全字母、isdigit()全数字、isalnum()字母或数字、isspace()全空白、islower()全小写、isupper()全大写、istitle()标题格式、isdecimal()十进制数字、isnumeric()数字字符、isascii()全ASCII。密码复杂度校验可以组合len()和any()使用。
  1. print('abc'.isalpha())    # True
  2. print('123'.isdigit())    # True
  3. print('abc123'.isalnum()) # True
  4. print(' '.isspace())      # True
  5. print('abc'.islower())    # True
  6. print('ABC'.isupper())    # True
  7. print('Abc'.istitle())    # True
  8. print('123'.isdecimal())  # True
  9. print('123'.isnumeric())  # True
  10. print('abc'.isascii())    # True
  11. def validate_password(password):
  12.     if len(password) < 8:
  13.         return False, '密码至少8位'
  14.     if not any(c.isupper() for c in password):
  15.         return False, '密码必须包含大写字母'
  16.     if not any(c.islower() for c in password):
  17.         return False, '密码必须包含小写字母'
  18.     if not any(c.isdigit() for c in password):
  19.         return False, '密码必须包含数字'
  20.     return True, '密码符合要求'
  21. print(validate_password('abc'))
  22. print(validate_password('abcdefgh'))
  23. print(validate_password('Abcdefgh1'))
复制代码

七、实践选择清单

需要多行文本或文档字符串时用三引号;路径和正则优先用r-string,但末尾不能是单个反斜杠;需要格式化输出时用f-string,Python 3.6+可用,调试写法需要3.8+;需要把其他类型转成字符串时用str(),自定义类同时实现__str__和__repr__;少量拼接可用+,大量拼接用列表收集后join();处理文件、网络和数据库文本时明确编码,读写两端保持一致;密码或格式校验可组合is系列方法和any()。这些选择都围绕原文示例中的事实:字符串不可变、转义规则、编码差异和join的分配方式。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-10-20 13:48 , Processed in 0.030228 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部