python实训的意义_[Python] 一个让我更加清楚地理解了字典的实验……

背景

由于一些安全上的要求,笔者所在公司在阿里云上的主机都要写白名单ACL。其中一个安全组中有监控的脚本需要发消息给企业微信,然后就犯了难——企业微信并没有接口告诉我们它的URL最后会解析为哪些ip,虽然确实有一个ip接口会给一个ip列表,但那个列表用在回调的情况下,和我们直接向企业微信发送HTTP请求时解析出来的ip并不一样

好在,我找到了这么个东西——企业微信域名IP列表​res.mail.qq.com

不过,这里面关于api接口所能解析出来的ip也多的让人眼花,一个个去配策略怕是配到死去了,于是就想用阿里云上的安全组策略的json模板,把这些ip填充进去生成个json文件,这样就可以直接导入策略了……

写出了Bug……

想法有了就开干。

写出来的代码是这样的——

import json

ips = '101.89.18.158,183.57.48.50,183.61.49.203,59.37.116.103,59.37.96.203,59.37.96.177,183.3.224.149,183.3.234.106,' \

'219.133.60.224,59.37.116.102,101.227.162.152,101.226.49.50,163.177.56.117,140.207.189.106,220.249.243.155,' \

'157.255.173.237,58.251.80.106,58.251.61.195,223.167.84.62,116.128.138.160,220.249.243.71,163.177.72.150,' \

'163.177.83.223,163.177.90.33,183.232.95.169,117.184.242.103,183.192.202.172,183.232.94.38,183.232.126.25,' \

'183.232.119.142,183.232.95.88,183.232.88.200,183.232.126.115,121.51.86.66,182.254.34.111,121.51.130.85,' \

'182.254.34.156,182.254.34.69,182.254.78.66,203.205.255.254,182.254.34.63,182.254.38.24,203.205.219.41,' \

'121.51.140.149,182.254.38.32,182.254.5.199,182.254.11.176'

ipslist = ips.split(",")

PolicyList = []

DictTemplate = {

"Policy": "Accept",

"Description": "访问微信接口",

"Priority": 1,

"NicType": "intranet",

"Direction": "egress",

"PortRange": "443/443",

"IpProtocol": "TCP",

"DestCidrIp": ""

}

for i in range(len(ipslist)):

DictTemplate["DestCidrIp"] = ipslist[i] + "/32"

PolicyList.append(DictTemplate)

print(json.dumps(PolicyList, ensure_ascii=False, indent=2))

当然,毫无疑问的,这个代码的运行是有问题的……

[

{

"Policy": "Accept",

"Description": "访问微信接口",

"Priority": 1,

"NicType": "intranet",

"Direction": "egress",

"PortRange": "443/443",

"IpProtocol": "TCP",

"DestCidrIp": "182.254.11.176/32"

},

{

"Policy": "Accept",

"Description": "访问微信接口",

"Priority": 1,

"NicType": "intranet",

"Direction": "egress",

"PortRange": "443/443",

"IpProtocol": "TCP",

"DestCidrIp": "182.254.11.176/32"

},

{

"Policy": "Accept",

"Description": "访问微信接口",

"Priority": 1,

"NicType": "intranet",

"Direction": "egress",

"PortRange": "443/443",

"IpProtocol": "TCP",

"DestCidrIp": "182.254.11.176/32"

},

......

]

"DestCidrIp" 的值是一样的……Why?

因为这里——

for i in range(len(ipslist)):

DictTemplate["DestCidrIp"] = ipslist[i] + "/32"

PolicyList.append(DictTemplate)

起初我以为,只要这样子,就可以把IP循环变成字典,然后插入到新的列表中,当然,实际上不行,因为我并非把某个值插入到了新的列表里,而是把整个字典对象放入了列表里,换言之,我的列表里实际的内容等于是——

[DictTemplate, DictTemplate, DictTemplate, DictTemplate, ......]

所以,每次循环,DictTemplate发生变化,列表里所有的元素都会变化……结果就是我输出的列表中的所有元素都一样,因为它们本来就是对应了同一个对象

当我操作一个列表的时候,我会用索引来访问值,而当我需要构建一个完整的字典的时候,我不可能只需要字典的值,字典里的键同样是我需要的东西,但是如果像上面这样做,结果就是我只是在重复的导入同一个对象,故而列表中充斥着同样的元素

修Bug……

知道了错在哪,问题就好解决了,Python的字典类型有个方法,copy()

for i in range(len(ipslist)):

DictTemplateCopy = DictTemplate.copy()

DictTemplateCopy["DestCidrIp"] = ipslist[i] + "/32"

PolicyList.append(DictTemplateCopy)

在操作字典对象之前,创建一个浅复制的对象,然后对这个对象进行操作并插入到列表中,再次循环的时候会再次创建另一个浅复制的对象,当然,之前那个对象就消失了

在交互式解释器里可以做这样一个实验

>>> DictTemplate = {

... "Policy": "Accept",

... "Description": "访问微信接口",

... "Priority": 1,

... "NicType": "intranet",

... "Direction": "egress",

... "PortRange": "443/443",

... "IpProtocol": "TCP",

... "DestCidrIp": ""

... }

>>>

>>> copy = DictTemplate.copy()

>>> print(id(copy))

2109669840920

>>> copy = DictTemplate.copy()

>>> print(id(copy))

2109670360392

>>> copy = DictTemplate.copy()

>>> print(id(copy))

2109669840920

>>> copy = DictTemplate.copy()

>>> print(id(copy))

2109670360392

不难看出,每次执行 copy = DictTemplate.copy() 后,打印其内存地址,该地址至少和上一次是不一样的。放在for循环里,就等于每次都是一个新的对象。

如此一来,执行结果就正常了——

[

{

"Policy": "Accept",

"Description": "访问微信接口",

"Priority": 1,

"NicType": "intranet",

"Direction": "egress",

"PortRange": "443/443",

"IpProtocol": "TCP",

"DestCidrIp": "101.89.18.158/32"

},

{

"Policy": "Accept",

"Description": "访问微信接口",

"Priority": 1,

"NicType": "intranet",

"Direction": "egress",

"PortRange": "443/443",

"IpProtocol": "TCP",

"DestCidrIp": "183.57.48.50/32"

},

{

"Policy": "Accept",

"Description": "访问微信接口",

"Priority": 1,

"NicType": "intranet",

"Direction": "egress",

"PortRange": "443/443",

"IpProtocol": "TCP",

"DestCidrIp": "183.61.49.203/32"

},

{

"Policy": "Accept",

"Description": "访问微信接口",

"Priority": 1,

"NicType": "intranet",

"Direction": "egress",

"PortRange": "443/443",

"IpProtocol": "TCP",

"DestCidrIp": "59.37.116.103/32"

},

{

"Policy": "Accept",

"Description": "访问微信接口",

"Priority": 1,

"NicType": "intranet",

"Direction": "egress",

"PortRange": "443/443",

"IpProtocol": "TCP",

"DestCidrIp": "59.37.96.203/32"

},

......

]

P.S. 日常写代码习惯于把功能都封装在模块里,模块之间变量隔离,因此就不会碰到这个情况。如果每次append的对象都是函数调用返回的结果,那么每次append进去的,一定是不同的对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值