python for循环remove同一个list过程解析

作者:urey_pp 时间:2023-03-20 22:07:48 

下午在用python将Linux的conf配置文件转化成字典dict时遇到了一个奇怪的问题,原先conf配置文件中没有注释行(以#开头的行),后来为了避免这种情况,添加了一个对以#开头的行删除的操作。 实践结果颠覆了已有的认知,直接上代码示例。

代码片段1


#!/usr/bin/python
# encoding: utf-8  
# -*- coding: utf8 -*-  
import re  
list_to_test = ['# ', '# conf', 'NAME="Ubuntu"', 'VERSION="14.04.3 LTS, Trusty Tahr"']  
for member in list_to_test:  
if re.search('^#+.*', member) is not None:  
 list_to_test.remove(member)  
print list_to_test

结果1:

['# conf', 'NAME="Ubuntu"', 'VERSION="14.04.3 LTS, Trusty Tahr"']

代码片段2


#!/usr/bin/python
# encoding: utf-8  
# -*- coding: utf8 -*-  
list_to_test = ['# ', '# conf', 'NAME="Ubuntu"', 'VERSION="14.04.3 LTS, Trusty Tahr"']  
list_to_test.remove('# ')  
list_to_test.remove('# conf')  
print list_to_test

# 结果2:

['NAME="Ubuntu"', 'VERSION="14.04.3 LTS, Trusty Tahr"']

本以为上述两个代码的结果应该是一样的,结果不一样。

分析:

原因是不能在for循环中用remove同一个列表(遍历中删除)。当remove这个list中的元素时,list的长度发生了变化,for循环就会受到影响(这个python版本(2.7.x没有明显的报错,可能作者并不认为这是一个issue或bug,但给点提示也是好的啊)。

解决办法:

用一个新的列表(list)去代替循环中的list或者代替remove操作的list。在创建新的列表是可以用cpoy模块中的deepcopy方法也可以用new_list = old_list[:]的方法,如下:


#!/usr/bin/python
# encoding: utf-8
# -*- coding: utf8 -*-
import re
from copy import deepcopy

old_list = ['# ', '# conf', 'NAME="Ubuntu"', 'VERSION="14.04.3 LTS, Trusty Tahr"']
new_list = deepcopy(old_list)
for member in new_list:
if re.search('^#+.*', member) is not None:
 old_list.remove(member)
print old_list

有趣(令人困惑)的是切片也是浅复制,但利用切片也可以实现上述功能,代码如下:


#!/usr/bin/python
# encoding: utf-8
# -*- coding: utf8 -*-
import re
old_list = ['# ', '# conf', 'NAME="Ubuntu"', 'VERSION="14.04.3 LTS, Trusty Tahr"']
new_list = old_list[:]
for member in new_list:
if re.search('^#+.*', member) is not None:
 old_list.remove(member)
print old_list

上述导致错误发生的例子(在for循环中用remove同一个列表)可以认知为这个操作是修改对象势必影响此对象,要想修改一个对象却不影响此对象引用,则需要对象复制。如果你想修改一个对象,而且想让原始的对象不受影响,那你就需要对象复制。

附加知识点:

关于浅复制(浅拷贝)

对象的浅复制(shallow copy):它虽然复制了对象,但对于对象中的元素,依然使用引用.

(1)、使用切片[:]操作进行拷贝 (注释:切片只复制了对象的顶层,对对象的下一层还是引用,举个例子:[1,2,3,[4,5,6]])

(2)、使用工厂函数(如list/dir/set)等进行拷贝

(3)、copy.copy()

(4)、=(赋值)操作(注释:原文没有,此处是新添加的,根据“对象的赋值实际上是对象的引用”添加)

如果希望复制一个容器对象,以及它里面的所有元素(包含元素的子元素),使用copy.deepcopy这个方法会消耗一些时间和空间。不过,如果你需要完全复制,这是唯一的方法。

注意:

1、对于非容器类型(如数字、字符串、和其他‘原子'类型的对象)没有被拷贝一说。

2、如果元组变量只包含原子类型对象,则不能深copy。

来源:https://blog.51cto.com/dgd2010/1811590

标签:python,for,循环,remove,list
0
投稿

猜你喜欢

  • python区块及区块链的开发详解

    2023-07-05 16:26:36
  • python实现单张图像拼接与批量图片拼接

    2023-07-28 12:33:36
  • MySQL连接时出现2003错误的实现

    2024-01-22 17:17:30
  • Python学习入门之区块链详解

    2021-07-15 18:21:55
  • 通过按钮实时切换CSS样式 实现CSS换肤的实例

    2008-07-17 12:55:00
  • MySQL下载安装、配置与使用教程详细版(win7x64)

    2024-01-22 16:44:50
  • Pytest+request+Allure实现接口自动化框架

    2023-08-12 17:29:33
  • Python抽象类应用详情

    2022-03-24 17:41:13
  • python利用K-Means算法实现对数据的聚类案例详解

    2021-02-28 10:01:29
  • PHP错误提示的关闭方法详解

    2023-11-14 13:00:05
  • 一文带你吃透Python中的日期时间模块

    2023-01-11 19:33:32
  • Python 基于jwt实现认证机制流程解析

    2022-07-15 00:25:30
  • python flask安装和命令详解

    2022-07-25 10:42:10
  • Python实现邮件自动下载的示例详解

    2023-06-15 04:44:35
  • vue2.0 可折叠列表 v-for循环展示的实例

    2024-04-28 09:32:22
  • SQL 比较一个集合是否在另一个集合里存在的方法分享

    2011-12-01 10:19:26
  • Linux安装Python虚拟环境virtualenv的方法

    2022-07-07 00:33:36
  • python用pandas数据加载、存储与文件格式的实例

    2021-09-05 03:44:47
  • python实现简易的学生信息管理系统

    2021-08-24 12:07:09
  • Python实现我的世界小游戏源代码

    2023-07-26 02:09:08
  • asp之家 网络编程 m.aspxhome.com