要说在 Python 里干活,哪个操作频率高?“追加”绝对算一个!你想想看,处理日志文件得往里头追加新记录吧?收集用户输入,得往列表里追加数据吧?构建一大段文本信息,比如邮件或者报告,那不就是字符串的追加拼接嘛?这事儿看似简单,细究起来,门道可不少。而且不同类型的对象,“追加”的方式和背后的逻辑,那可是大大的不一样,甚至有些是你一开始想不到的坑。
咱们先聊聊最常见的,往文件里头追加。这简直是家常便饭,特别是那些需要持续记录、不覆盖原有内容的应用场景。比如服务器跑着,各种事件哗啦哗啦进来,总得找个地方记下来吧?日志文件就是最典型的例子。在 Python 里,你要往文件末尾追加内容,用的就是 open()
函数,但关键在于那个模式参数。平时咱们读文件用 'r'
,写文件覆盖原有内容用 'w'
,而追加,记住啦,是 'a'
模式。
'a'
模式,全称 append,就是追加的意思。当你用 'a'
模式打开一个文件时,如果文件存在,光标会自动移到文件的末尾;如果文件不存在,Python 会帮你新建一个空的。接着你就可以用 write()
方法往里头写东西了,写下的内容会紧跟在文件原有内容的后面。别小看这 'a'
,它跟 'w'
的区别大了去了。用 'w'
打开,不管文件里原来有啥,咔嚓一下全给你清空,然后从头开始写。而 'a'
呢,就是“和气生财”,只管在后面添砖加瓦,绝不破坏“历史”。
写文件的基本操作,我相信你肯定知道,就是 with open('你的文件名.txt', 'a', encoding='utf-8') as f:
这么一套。用 with
语句是强烈推荐的好习惯,能确保文件用完后自动关闭,就算中间程序抛异常了也一样,省得你操心 f.close()
那点事儿。至于 encoding='utf-8'
,这玩意儿太重要了!特别是处理包含中文或其他非 ASCII 字符的内容时,如果编码不对,写进去的文件打开一看就是乱码,或者直接报错。别问我怎么知道的,当年踩过的编码坑,那可真是眼泪两行。尤其是 Windows 和 Linux/macOS 对默认编码的处理还不太一样,显式指定 utf-8
能省掉你一大堆麻烦。
往文件里追加内容,通常用 f.write()
。比如你想记录一条日志:“[2023-10-27 10:00:00] 用户 XXX 登录成功”。你就 f.write('[2023-10-27 10:00:00] 用户 XXX 登录成功')
。但是等等,写完这一行,下一条日志该怎么写?直接接着写吗?那文件内容就全挤在一行了,没法看!所以啊,别忘了那个小小的、不起眼的,但至关重要的换行符!在大多数系统里是 \n
。写一条记录,记得在末尾追加一个 '\n'
,就像这样:f.write('你想写的内容' + '\n')
。或者更清晰点:f.write('你想写的内容\n')
。有时候你有一堆行要写,可以用 f.writelines(list_of_strings)
,注意 writelines
不会自动加换行符,你的字符串列表里每个字符串末尾都得自带 \n
。换行符这个事儿,在不同操作系统下还可能不一样(比如 Windows 是 \r\n
),不过 Python 在文本模式下打开文件时(也就是没加 'b'
),通常会帮你自动处理换行符的转换,所以用 '\n'
在代码里是跨平台的最佳实践,但追加时千万别忘了它,否则文件会变得非常非常难读。
好,文件这块儿算是说清楚了。那除了文件,咱们写 Python 代码,跟什么打交道最多?毋庸置疑,是各种数据结构,特别是列表(list)。列表的“追加”操作,简直是日常开发中用得最多的功能之一。Python 的列表设计得非常灵活,可以装任意类型的数据,而且是动态大小的,需要往里头加东西?简单得不能再简单了。
列表追加,第一个想到的,也是最直接的方法,就是 append()
。这个方法啊,就是专门用来往列表的末尾追加一个元素的。比如你有个空列表 my_list = []
,你想往里加个数 1
,那就 my_list.append(1)
,现在 my_list
就是 [1]
了。再加个字符串 'hello'
?my_list.append('hello')
,现在 my_list
变成 [1, 'hello']
了。很简单对吧?append()
就是把括号里你给它的东西,整个儿作为一个单一的元素,扔到列表的最后。
但是!这里有个小细节,也是新手刚开始容易犯迷糊的地方。如果你 append()
的是一个列表或者其他可迭代对象,比如 my_list.append([2, 3])
,结果会是啥?my_list
会变成 [1, 'hello', [2, 3]]
。看到没?那个 [2, 3]
整个儿被当成一个元素加进去了,列表的长度只增加了 1。
那如果我想把一个列表里的所有元素,一个一个地加到另一个列表的末尾呢?这时候就轮到 extend()
方法出场了。extend()
方法接受一个可迭代对象(比如另一个列表、元组、字符串等等),然后把你给它的这个可迭代对象里的所有元素,逐个地追加到当前列表的末尾。还是上面的 my_list
,如果我们执行 my_list.extend([2, 3])
,结果会是 [1, 'hello', 2, 3]
。注意对比啊,这次 2
和 3
是作为单独的元素加进来的,列表的长度增加了 2。理解 append()
和 extend()
的区别,是你玩转列表追加的关键。我刚学那会儿,老是记混,导致结果不是我想要的,得花时间去排查。现在想想,其实很简单,append
加“一个”,extend
加“一批”。
除了 append()
和 extend()
,其实还有别的方法也能实现列表追加,比如用加号 +
运算符。你可以用列表相加的方式实现拼接:list1 = [1, 2]
, list2 = [3, 4]
, new_list = list1 + list2
。结果 new_list
就是 [1, 2, 3, 4]
。这个方法看起来直观,用起来也挺方便,但要注意一点:list1 + list2
并不是在 list1
或 list2
原地修改后返回,而是创建了一个全新的列表来存放拼接后的结果。对于小列表来说这点性能开销几乎可以忽略,但如果你的列表非常大,而且需要频繁进行追加(拼接)操作,用 +
可能会比 append
或 extend
效率低不少,因为每次都会创建新对象。所以,如果在原列表上修改(in-place modification)是你需要的,append
和 extend
是更好的选择。
聊完列表,再来说说字符串。字符串的“追加”,或者说拼接,也是我们经常干的事情。但是!这里有个非常非常重要的概念要先讲明白:在 Python 里,字符串是不可变的(immutable)。啥意思?就是一旦一个字符串对象被创建出来,它的内容就不能被改变了。你所有看起来像是“修改”或者“追加”字符串的操作,比如 s = s + 'world'
,实际上都不是在原来的 s
上改的,而是 Python 在后台偷偷创建了一个全新的字符串对象,包含了原来 s
的内容和你要追加的内容,然后再把 s
这个名字指向新创建的那个字符串对象。原来的那个字符串对象?没人引用它了,等着被垃圾回收吧。
理解了字符串的不可变性,你就能明白为什么用加号 +
来拼接字符串,在拼接次数不多的时候挺方便,比如 'hello' + ' ' + 'world'
结果是 'hello world'
。但如果你有一个列表,里面有几万个字符串,你想把它们全拼接到一块儿,如果用一个循环,每次都 result = result + item
这种方式,那效率会非常非常低。想想看,每次循环都要创建一个新的字符串对象,销毁旧的,这开销得多大啊!
这时候,Python 给你准备了一个“大杀器”,专门用来高效拼接大量字符串——就是字符串对象的 join()
方法!这个方法呀,是字符串界里处理“追加”的利器。它的用法有点特别,是这样子的:separator.join(iterable_of_strings)
。separator
是一个字符串,用来连接 iterable_of_strings
里头的每个元素,而 iterable_of_strings
顾名思义,是一个包含字符串的可迭代对象,比如一个字符串列表或者元组。举个例子,如果你有个列表 words = ['Hello', 'Python', 'World']
,你想用空格把它们连起来,就这么写:' '.join(words)
,结果就是 'Hello Python World'
。如果想用逗号加空格连:', '.join(words)
,结果 'Hello, Python, World'
。如果想无缝连接:''.join(words)
,结果 'HelloPythonWorld'
。用 join()
方法来拼接大量字符串,效率比用 +
高出好几个数量级,因为它在内部会更聪明地处理内存分配,避免了频繁创建和销毁临时字符串对象。所以在需要追加大量字符串时,无脑用 join()
就对了!
除了文件、列表、字符串这三大件,Python 里还有字典(dict)和集合(set)这两种常用数据结构,它们也有类似“追加”或者说“添加/更新”的操作。
对于字典,它存储的是键值对。往字典里“追加”一个元素,其实就是添加一个新的键值对,或者更新一个已有键的值。最简单的方式就是直接赋值:my_dict = {'a': 1}
,你想加一个键 'b'
值为 2
,就 my_dict['b'] = 2
,现在 my_dict
就是 {'a': 1, 'b': 2}
了。如果键 'a'
已经存在,你再 my_dict['a'] = 10
,那么原来 'a': 1
就会被更新成 'a': 10
。这既是添加,也是更新,看你操作的键存不存在。
字典还有个update() 方法,可以用来“追加”或更新多个键值对。update()
可以接受另一个字典作为参数,也可以接受一个键值对的可迭代对象(比如元组的列表 [('b', 2), ('c', 3)]
或者关键字参数 b=2, c=3
)。比如 my_dict = {'a': 1}
,执行 my_dict.update({'b': 2, 'c': 3})
,结果 my_dict
变成 {'a': 1, 'b': 2, 'c': 3}
。如果更新的字典里有和原字典重复的键,比如 my_dict.update({'a': 10, 'd': 4})
,那么 'a'
的值会被更新,同时追加新的键 'd'
,结果是 {'a': 10, 'b': 2, 'c': 3, 'd': 4}
。所以字典的update,也是一种非常灵活的“追加”方式。
最后简单说说集合(set)。集合是一组无序且唯一的元素。往集合里“追加”元素,叫做添加。集合提供了 add()
方法用来添加单个元素:my_set = {1, 2}
,my_set.add(3)
,结果 my_set
是 {1, 2, 3}
。如果添加的元素已经在集合里了,比如 my_set.add(2)
,集合内容不会变,因为集合里的元素必须是唯一的。
如果想往集合里添加多个元素,可以用update() 方法。集合的 update()
方法和字典的类似,接受一个可迭代对象作为参数,然后把这个可迭代对象里的所有元素逐个添加到当前集合里。比如 my_set = {1, 2}
,my_set.update([3, 4, 2])
,结果 my_set
会变成 {1, 2, 3, 4}
(注意 2
只出现一次)。
看到没?Python 里“追加”这个概念,根据操作对象的不同,具体实现方式和背后的原理那真是五花八门。文件有特定的模式 'a'
,列表有 append
和 extend
的区分,字符串因为不可变性催生了 join
这样的高效方法,字典和集合则用 update
来批量添加。掌握这些不同的“追加”姿势,根据你实际处理的数据类型和场景选择最合适、最高效的方法,你的 Python 代码才能写得又顺溜又漂亮。别怕踩坑,多练多试,这些操作慢慢就刻进DNA里了。
评论(0)