Python可变数据类型list填坑一则
前提概要
最近写业务代码时遇到一个列表的坑,在此记录一下。
需求
现在有一个普通的rule列表:
rule = [["ID",">",0]]
在其他地方经过计算得到一个id_lst的列表:
id_lst = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
使用小范围的数模拟一下真实的业务场景:我需要再在前面的rule的基础上新加另外一个规则列表,但是id_lst的长度不能超过5。
还是看最终拼接的效果吧:
ret = [
[['ID', '>', 0], ['ID', 'in', [1, 2, 3, 4, 5]]],
[['ID', '>', 0], ['ID', 'in', [6, 7, 8, 9, 10]]],
[['ID', '>', 0], ['ID', 'in', [11, 12, 13, 14, 15]]],
[['ID', '>', 0], ['ID', 'in', [16, 17, 18, 19,20]]]
]
也就是说,我需要吧id_lst中的数按照5位基数进行分割,放在新的规则列表中,然后与之前的rule组成新的规则...以此类推,把“新组装成的规则”再放到新的列表ret中。
—— 抛开业务场景,这个问题其实可以模拟成一个小问题:条件是rule与id_lst,需要得到ret那种样式的结果。
错误的解决方法
看到这种问题,那肯定得遍历呗,所以第一版年轻的程序诞生了:
# -*- coding:utf-8 -*-
rule = [["ID",">",0]]
id_lst = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
append_lst = []
ret = [] for i in range(len(id_lst)//5 + 1):
ll = id_lst[i*5:(i+1)*5]
# print("ll:",ll)
append_rule = []
if len(ll) != 0:
append_rule = ["ID","in",ll]
append_lst.append(append_rule) print("append_lst:",append_lst)
# [['ID', 'in', [1, 2, 3, 4, 5]], ['ID', 'in', [6, 7, 8, 9, 10]], ['ID', 'in', [11, 12, 13, 14, 15]], ['ID', 'in', [16, 17, 18, 19, 20]], []] if len(append_lst) == 1:
rule += append_lst
ret.append(rule)
else:
for i in append_lst:
# 排除空值的干扰
if i == []:
append_lst.pop(append_lst.index(i))
continue
rule.append(i)
ret.append(rule)
rule.pop()
print(">>>>>ret:",ret)
# [[['ID', '>', 0]], [['ID', '>', 0]], [['ID', '>', 0]], [['ID', '>', 0]]]
结果竟然不是自己想的辣样!
当时我还以为是for循环遍历的“姿势”不对,于是乎试图使用“堆栈”的方式解决:
# -*- coding:utf-8 -*-
rule = [["ID",">",0]]
id_lst = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
append_lst = []
ret = [] for i in range(len(id_lst)//5 + 1):
ll = id_lst[i*5:(i+1)*5]
# print("ll:",ll)
append_rule = []
if len(ll) != 0:
append_rule = ["ID","in",ll]
append_lst.append(append_rule) print("append_lst:",append_lst)
# [['ID', 'in', [1, 2, 3, 4, 5]], ['ID', 'in', [6, 7, 8, 9, 10]], ['ID', 'in', [11, 12, 13, 14, 15]], ['ID', 'in', [16, 17, 18, 19, 20]], []]
# 堆栈的方式解决
while append_lst:
a_l = append_lst.pop(0)
# 排除空列表做一下判断
if a_l:
rule.append(a_l)
ret.append(rule)
rule.pop() print(">>>>>ret:",ret)
# [[['ID', '>', 0]], [['ID', '>', 0]], [['ID', '>', 0]], [['ID', '>', 0]]]
问题分析
其实细看下来,用for循环遍历与用堆栈的方式解决的思路是一样的:遍历的每一次把append_lst中的每一个列表元素加到rule列表中,然后把新得到的这个rule列表加在ret中!最后因为我们要“重复利用rule列表,”为了防止“重复”数据,将之前append到rule列表中的元素pop出去,然后再进行新一轮的操作。
于是乎自己用Pycharm来debug了一下,终于发现了问题:原来每一次append到ret列表中的那个rule列表,跟原来的rule列表其实是同一个列表!(惊不惊喜,意不意外0-0)—— ret.append(rule)这个操作应该只是将rule列表的引用传递进去了,最后那个rule.pop()操作改变了rule本身的值,同样也改变了ret中之前append进去的rule!
下面是我debug的过程,大家仔细看倒数第二行ret的值的变化过程:

问题解决
既然放在ret中的rule列表与原rule列表是一样的,那么可以使用deepcopy将临时生成的列表放在ret中,这样在rule.pop()后就不会改变之前append到ret中的那个列表了:
# -*- coding:utf-8 -*-
from copy import deepcopy rule = [["ID",">",0]]
id_lst = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
append_lst = []
ret = [] for i in range(len(id_lst)//5 + 1):
ll = id_lst[i*5:(i+1)*5]
# print("ll:",ll)
append_rule = []
if len(ll) != 0:
append_rule = ["ID","in",ll]
append_lst.append(append_rule) print("append_lst:",append_lst)
# [['ID', 'in', [1, 2, 3, 4, 5]], ['ID', 'in', [6, 7, 8, 9, 10]], ['ID', 'in', [11, 12, 13, 14, 15]], ['ID', 'in', [16, 17, 18, 19]]]
# append_lst等于1不用切割,这里为了后期容易维护我把不分割与分割的情况分开写了
if len(append_lst) == 1:
rule += append_lst
ret.append(rule)
else:
for i in append_lst:
if i == []:
append_lst.pop(append_lst.index(i))
continue
rule.append(i)
current_lst = deepcopy(rule)
ret.append(current_lst)
rule.pop()
print(">>>>>ret:",ret)
# [[['ID', '>', 0], ['ID', 'in', [1, 2, 3, 4, 5]]], [['ID', '>', 0], ['ID', 'in', [6, 7, 8, 9, 10]]], [['ID', '>', 0], ['ID', 'in', [11, 12, 13, 14, 15]]], [['ID', '>', 0], ['ID', 'in', [16, 17, 18, 19, 20]]]]
for i in ret:
print(i)
"""
[['ID', '>', 0], ['ID', 'in', [1, 2, 3, 4, 5]]]
[['ID', '>', 0], ['ID', 'in', [6, 7, 8, 9, 10]]]
[['ID', '>', 0], ['ID', 'in', [11, 12, 13, 14, 15]]]
[['ID', '>', 0], ['ID', 'in', [16, 17, 18, 19, 20]]]
"""
存在问题
关于Python中赋值与拷贝问题我之前总结过一篇博客:Python3中的赋值操作、浅拷贝与深拷贝
也许经验丰富的你从上面的代码中也看出了问题:如果实际中id_lst中的数据非常大(几十万甚至更多),而且我们以万为基数进行分割的话,deepcopy出来的这个current_lst会占用比较大的空间!
如果聪明的你有更好的解决方式的话,欢迎在下方留言,一起交流探讨。
Python可变数据类型list填坑一则的更多相关文章
- python 可变数据类型和不可变数据类型(7)
python数据类型分别有整数int / 浮点数float / 布尔值bool / 元组tuple / 列表list / 字典dict,其中数据类型分为两个大类,一种是可变数据类型:一种是不可变数据类 ...
- python 可变数据类型&不可变数据类型
在python中,数据类型分为可变数据类型和不可变数据类型,不可变数据类型包括string,int,float,tuple,可变数据类型包括list,dict. 所谓的可变与不可变,举例如下: > ...
- python可变数据类型和不可变数据类型
1.可变数据类型:在id不变的情况下,value可改变(列表和字典是可变类型,但是字典中的key值必须是不可变类型) 2.不可变数据类型:value改变,id也跟着改变.(数字,字符串,布尔类型,都是 ...
- python 可变数据类型 和 不可变数据类型
在 python 中,类型属于对象,变量是没有类型的: a=[1,2,3] a="Runoob"以上代码中,[1,2,3] 是 List 类型,"Runoob" ...
- Python 可变数据类型与不可变数据类型
浅拷贝和深拷贝 Python数据都是存放到内存中的,Python的数据又分为可变和不可以变 可变数据(修改了值后,不会改变内存地址,修改的值还是指向相同的内存地址) 字典 # 列表是可变 x = [1 ...
- python的可变与不可变数据类型
<python的可变与不可变数据类型> python与C/C++不一样,它的变量使用有自己的特点,当初学python的时候,一定要记住“一切皆为对象,一切皆为对象的引用”这句话,其 ...
- python基础之可变数据类型与不可变数据类型
一.什么可变数据类型和不可变数据类型 可变数据类型:value值改变,id值不变:不可变数据类型:value值改变,id值也随之改变. 二.如何确定一种数据类型是可变的还是不可变的 根据可变数据类型与 ...
- python中不可变数据类型和可变数据类型
在学习python过程中我们一定会遇到不可变数据类型和可变数据类型. 1.名词解释 以下所有的内容都是基于内存地址来说的. 不可变数据类型: 当该数据类型的对应变量的值发生了改变,那么它对应的内存地址 ...
- python的可变数据类型和不可变类型
python里面一切皆对象 ython的每个对象都分为可变类型和不可变类型 整形,浮点型,字符串,元组属于不可变类型,列表,字典是可变类型 不可变数据类型 对不可变类型的变量重新赋值,实际上是重新创建 ...
随机推荐
- 04.AutoMapper 之投影(Projection)
https://www.jianshu.com/p/031553705417 投影(Projection) 投影将源转换为目标而不是扁平化对象模型.如果没有额为的配置AutoMapper需要一个扁平化 ...
- homebrew学习(三)之homebrew命令
安装homebrew: /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/m ...
- c#HtmlAgilityPack解析html
通过HtmlAgilityPack实现对html页面解析HtmlDocument doc = new HtmlDocument(); doc.Load(yourStream); var itemLis ...
- 使用Servlet实现验证码
没有验证码带来的问题 对特定用户不断登录破解密码. 对某个网站创建账户. 对某个网站提交垃圾数据. 对某个网站刷票. 通过验证码由用户肉眼识别其中的验证码信息,从而区分用户是人还是计算机. 定义: ...
- vue 简介 vue 项目 组件
1. 概念 Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架.能够为复杂的单页应用提供驱动. 2. 用法 2.1 声明式渲染 2.1.1 改变文本 {{ m ...
- Redis启动方式
一.前端启动 直接运行bin/redis-server将以前端模式启动.[bin目录是在/usr/local/redis/bin] # ./redis-server 启动缺点: ssh命令窗口关闭则r ...
- 002-Saltstack自动化操作记录(2)-配置使用
之前梳理了就是第一篇001,下面说说saltstack配置及模块使用: 为了试验效果,再追加一台被控制端minion机器192.168.1.118需要在master控制端机器上做好主机名映射关系 1 ...
- vue打包后element-ui部分样式(图标)异常问题
vue项目使用element-ui组件,打包后部分样式(上下左右箭头)异常,变成方框了. 页面报warn错误,有个字体找不到. 解决办法:在build文件夹下找到utils.js,加上一行public ...
- 如何使用windows performance recorder
先下载WPA TOOLS:从该地址下载,选最新的版本,然后可以只选择下载WPA工具 后面编写XML文件等等,可以参考这篇文章. 需要注意: 用管理员启动cmd后,如果想运行特定路径的文件,需要带上绝对 ...
- element-ui + redis + mongo + nuxt
用户注册: let {username,password} = req.body; let u = await UserModel.findOne({username}); if(u){ res.js ...