嘿,各位写代码的朋友们,咱们今天聊聊一个特基础,但又无处不在的事儿——拼接。你写 Python,哪怕是最简单的脚本,十有八九都得跟“拼接”打交道。说白了,就是把一堆零零散散的东西,比如字符串、列表里的元素、字典里的键值对,给“粘”一块儿,变成一个新的整体。

这事儿听起来挺简单,不就是个加号(+)的事儿嘛?刚开始学 Python 的时候,我也这么想,觉得 + 真是个万能灵药。两个字符串 "hello" + " world",得了,"hello world" 出来了。两个列表 [1, 2] + [3, 4],好家伙,[1, 2, 3, 4] 也齐活儿。那时候,我感觉自己掌握了宇宙真理,写啥都想着用 + 去拼。

但写着写着,就遇上事儿了。有一次我要处理一大堆从文件里读出来的文本行,大概几十万行吧,想把它们拼成一个大字符串。我理所当然地用了个循环,然后一行一行地用 + 往一个空字符串里加。刚开始还好,等行数一多,那速度简直了……就像蜗牛爬,眼瞅着程序在那里吭哧吭哧地跑,半天没反应。我当时都懵了,难道是我的电脑太烂?

后来才明白,原来 字符串拼接,尤其是用 + 在循环里反复操作,效率贼低!为啥?因为字符串在 Python 里是不可变的。你每次用 + 拼接,Python 都得在内存里重新创建一个新的字符串对象,把原来两个字符串的内容复制进去。你想啊,几十万次甚至更多次地创建、复制、再创建、再复制,那内存和CPU不就跟跑马拉松似的,累趴下了嘛。

这时候,我就学到了字符串拼接的第一个“神器”—— join() 方法。这玩意儿是字符串对象自带的方法,用法是 separator.join(sequence)。这里的 separator 是分隔符,sequence 是一个可迭代对象,比如列表、元组,里面装的是你要拼接的各个小字符串。join() 的厉害之处在于,它会先计算出最终拼接后字符串的总长度,然后一次性分配好内存,再把序列里的元素一股脑儿地复制进去。这效率,跟用 + 在循环里一点点加,简直是天壤之别!

举个例子:

“`python
lines = [‘第一行文本’, ‘第二行内容’, ‘第三行结束’]

如果用 + 在循环里拼,大概这样(别学!)

big_string = ”

for line in lines:

big_string += line + ‘\n’ # 每次都创建新字符串!

用 join() 就优雅多了

big_string = ‘\n’.join(lines) # 用换行符把列表里的字符串串起来
print(big_string)

输出:

第一行文本

第二行内容

第三行结束

“`

你看,用 join(),一行代码搞定,而且速度飞快。所以,以后碰到要拼接大量字符串,尤其是把列表、元组里的字符串拼起来,第一个想到的就应该是 .join()!这就像串珠子,不是一颗一颗地拿线穿(+),而是先把线准备好,然后把所有珠子一次性地串进去(join)。那感觉,舒坦!

除了 +join(),Python 还有几种更“讲究”的 字符串拼接 方式,与其说是拼接,不如说是格式化,也就是把一些变量的值“塞”到指定的字符串模板里。

最早接触的是 % 操作符,有点像 C 语言的 printf:

“`python
name = ‘张三’
age = 30
greeting = “你好,我是 %s,今年 %d 岁了。” % (name, age)
print(greeting)

输出:你好,我是 张三,今年 30 岁了。

“`

这个 % 操作符用起来也行,但格式符(%s, %d 等)记起来有点烦,而且参数多了得用元组包起来,有时候对不上号还容易出错。

接着出现了 str.format() 方法。这个就好用多了,用花括号 {} 作为占位符:

“`python
item = ‘苹果’
price = 5.5
message = “我买了一个 {},花了 {} 元。”.format(item, price)
print(message)

还可以指定位置或者用关键字参数

message_kw = “我买了一个 {0},花了 {1} 元。或者反过来:{1} 元买了 {0}。”.format(item, price)
print(message_kw)

message_named = “物品:{item_name},价格:{item_price} 元。”.format(item_name=item, item_price=price)
print(message_named)
“`

format() 方法比 % 灵活不少,可读性也好很多。但我得说,当我第一次看到 f-strings(格式化字符串字面量,Python 3.6+)的时候,简直惊为天人!这玩意儿太方便了,直接在字符串前面加个 fF,然后在花括号里写变量名或者表达式就行,写起来跟读起来一样自然:

“`python
name = ‘李四’
age = 25

f-string

greeting_f = f”你好,我是 {name},今年 {age} 岁了。”
print(greeting_f)

花括号里还能放表达式!

x = 10
y = 20
result = f”计算结果是:{x * y + 5}”
print(result)

甚至还能调用函数!

print(f”名字是:{name.upper()}”)
“`

用 f-strings,写需要包含变量的字符串简直是飞一般的体验,简洁、直观、高效(它在底层其实也做了优化)。现在我写 Python 3.6+ 的代码,几乎所有的字符串格式化和拼接都优先用 f-strings。强烈推荐!它不像 % 那么古老,也不像 format() 稍微有点啰嗦,f-string 就是那种“所见即所得”的畅快感。

好了, 字符串拼接 咱们大概就聊到这里。但“拼接”这事儿,可不光是字符串的专利。各种 数据结构 也经常需要“拼接”或“合并”。

比如 列表(list)。前面说了,可以用 +list1 + list2。但这会创建一个新的列表,如果列表很大,频繁这么做也会有性能开销。更常见的,如果你想把一个列表的内容“追加”到另一个列表的末尾,而不想创建新列表,可以用 extend() 方法

“`python
list_a = [1, 2, 3]
list_b = [4, 5, 6]

用 + (创建新列表)

list_c = list_a + list_b
print(f”用 + 拼接后:{list_c}”) # [1, 2, 3, 4, 5, 6]
print(f”原列表a:{list_a}”) # [1, 2, 3] 原来的没变

用 extend() (原地修改)

list_a.extend(list_b)
print(f”用 extend() 后:{list_a}”) # [1, 2, 3, 4, 5, 6] list_a 被修改了!
“`

extend() 的效率通常比 + 高,因为它是在原列表的内存空间后面直接追加元素(如果空间够的话),而不是新建一个。

还有一种“拼接”或者说“插入”的方式,是用切片赋值。你可以把另一个列表的内容插入到当前列表的任意位置:

python
list_nums = [1, 2, 5, 6]
list_middle = [3, 4]
list_nums[2:2] = list_middle # 在索引2的位置插入 list_middle 的内容
print(f"用切片赋值插入后:{list_nums}") # [1, 2, 3, 4, 5, 6]

这种方式非常灵活,能做到 extend() 做不到的中间插入。

至于 元组(tuple) 呢?因为它和字符串一样是不可变的,所以想要“拼接”两个元组,唯一的办法就是用 + 操作符,这同样会创建一个新的元组:

python
tuple_a = (10, 20)
tuple_b = (30, 40)
tuple_c = tuple_a + tuple_b
print(f"元组拼接:{tuple_c}") # (10, 20, 30, 40)

没别的招,不可变就是这样,要变只能重新造一个。

再看看 集合(set)。集合是用来装一堆不重复元素的“袋子”。拼接两个集合,其实就是取它们的并集。你可以用 union() 方法 或者 | 运算符 来创建一个新集合,包含两个集合的所有不重复元素:

“`python
set_a = {1, 2, 3}
set_b = {3, 4, 5}

用 union() (创建新集合)

set_c = set_a.union(set_b)
print(f”集合 union 后:{set_c}”) # {1, 2, 3, 4, 5}

用 | (创建新集合)

set_d = set_a | set_b
print(f”集合 | 后:{set_d}”) # {1, 2, 3, 4, 5}
“`

如果你想把一个集合的内容加到另一个集合里,原地修改原来的集合,可以用 update() 方法 或者 |= 运算符

“`python
set_x = {1, 2}
set_y = {2, 3, 4}

set_x.update(set_y)
print(f”集合 update() 后:{set_x}”) # {1, 2, 3, 4} set_x 被修改了!

set_p = {5, 6}
set_q = {6, 7, 8}
set_p |= set_q
print(f”集合 |= 后:{set_p}”) # {5, 6, 7, 8} set_p 被修改了!
“`

最后来说说 字典(dict) 的“拼接”,或者说合并。字典是一系列键值对的集合。合并字典时,如果遇到相同的键,后面的字典的值会覆盖前面字典的值。最常用的方法是 update() 方法

“`python
dict_a = {‘name’: ‘张三’, ‘age’: 30}
dict_b = {‘age’: 31, ‘city’: ‘北京’}

用 update() (原地修改 dict_a)

dict_a.update(dict_b)
print(f”字典 update() 后:{dict_a}”) # {‘name’: ‘张三’, ‘age’: 31, ‘city’: ‘北京’}
“`

update() 会把另一个字典的键值对添加到当前字典里,如果键冲突就覆盖。

在 Python 3.5+ 版本,还有一种很简洁的字典合并方式,用 ** 解包运算符

“`python
dict_x = {‘a’: 1, ‘b’: 2}
dict_y = {‘b’: 3, ‘c’: 4}

用 ** 解包 (创建新字典)

dict_z = {dict_x, dict_y}
print(f”字典 ** 解包合并后:{dict_z}”) # {‘a’: 1, ‘b’: 3, ‘c’: 4}
“`

这种方式特别好用,尤其当你需要合并多个字典,或者在创建一个新字典时同时从别的字典里“拷贝”一些内容过来。它会创建一个新的字典,非常“Pythonic”。

哎呀,说起来,还有一个特别特别重要的“拼接”场景,是很多人容易忽略或者做错的,那就是 文件路径的拼接!不同操作系统(Windows、macOS、Linux)的文件路径分隔符是不一样的(Windows 是 \,其他是 /)。如果你直接用字符串的 + 去拼路径,写死的 /\,那你的代码一换个操作系统就可能完蛋。

正确的姿势是使用 os.path.join() 函数

“`python
import os

比如要拼接目录 ‘my_folder’ 和文件名 ‘my_file.txt’

folder = ‘my_folder’
file_name = ‘my_file.txt’

错误示范 (依赖特定操作系统)

path_wrong = folder + ‘/’ + file_name # 在Windows上就错了

path_wrong = folder + ‘\’ + file_name # 在Linux/macOS上就错了

正确姿势

path_correct = os.path.join(folder, file_name)
print(f”正确拼接的文件路径:{path_correct}”) # 会根据当前系统自动使用正确的分隔符
“`

os.path.join() 会自动根据当前操作系统来选择合适的分隔符,太省心了。这是个小细节,但能避免不少跨平台的麻烦。

总结一下, 怎么拼接 python 里的各种东西,真不是一个 + 号就能包打天下的。字符串拼接有高效的 join() 和方便的 f-strings;列表有 extend() 和切片赋值;集合有 union()/|update()/|=;字典有 update()** 解包。还有处理文件路径的救星 os.path.join()

在我看来,选择哪种方法,取决于你的具体需求:
1. 你要拼接的是什么类型?字符串?列表?字典?
2. 你想要创建新的对象,还是原地修改原来的对象?(可变 vs 不可变在这里是关键!)
3. 你关不关心效率?大量操作时,join()extend()update() 通常比反复用 + 创建新对象要快得多。
4. 你追求代码的简洁性和可读性吗?f-strings 在格式化字符串方面简直无敌。

编程这事儿,很多时候就像做手工活儿,拼接就是把不同的零件组装起来。了解并熟练使用这些不同的“工具”(不同的拼接方法),能让你把代码写得更有效率、更健壮,也更漂亮。别怕一开始用错了或者选了低效的方法,多写多练,自然就有感觉了。毕竟,从踩过的坑里学到的,才是最扎实的经验嘛!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。