关于Python数组(List)循环添加对象遇到的问题-Python的深浅拷贝
  • 分类:Python
  • 发表:2019-03-21
  • 围观(3,907)
  • 评论(0)

问题来源

在爬取一个网站数据的时候,需要把每个页面的数据压缩为Json格式进行保存.我的做法是先将数据保存在dict内,再将dict插入到数组,最后通过json.dumps()将数据压缩为Json格式,具体数据流图如下:


详细代码:

detail = []
for station in stations.find_all("td"):
    if station.text.strip():
        detail.append(station.text.strip())

if not detail:
    continue

for num, key in enumerate(city_station_detail):
    city_station_detail[key] = detail[num]

# 将数据填充到result
city_detail["station_detail"].append(city_station_detail)

# 将result填充到results中
results.append(city_detail)

发现问题如下:

  1.  result内的数据都是detail的最后一组数据
  2.  results中的数据都是result的最后一组数据
{'city': '韶关', 'site': 'http://www.86pm25.com/city/shaoguan.html', 'time': '2019年03月21日 23时', 'quality': '52', 'station_detail': [{'station': '园林处', 'AQI': '52', 'PM2.5': '31μg/m³', 'PM10': '54μg/m³'}, {'station': '园林处', 'AQI': '52', 'PM2.5': '31μg/m³', 'PM10': '54μg/m³'}, {'station': '园林处', 'AQI': '52', 'PM2.5': '31μg/m³', 'PM10': '54μg/m³'}, {'station': '园林处', 'AQI': '52', 'PM2.5': '31μg/m³', 'PM10': '54μg/m³'}, {'station': '园林处', 'AQI': '52', 'PM2.5': '31μg/m³', 'PM10': '54μg/m³'}]

分析原因

在Python中一切皆为对象,在数据的填充过程中,append方法向list填充的是对象的地址,既数据的指针.由于多次循环填充的都是一个对象,所以list存放的是相同对象的指针,而不是真实数据.

即:list = [dict1, dict2, dict3, .......], 且: id(dict1) = id(dict2) = id(dict3)= .......

正是因为Python的这种特性导致最后的结果都是相同的数据,这个问题就是我们常说的Python的深浅拷贝问题.

直接赋值:其实就是对象的引用(别名)。

浅拷贝:数据半共享(复制其数据独立内存存放,但是只拷贝成功第一层)

深拷贝:数据完全不共享(复制其数据完完全全放独立的一个内存,完全拷贝,数据不共享)

问题解决

之所以遇到这个问题是因为上面的代码都是通过append实现,仅仅复制了数据的存放地址,并没有拷贝数据本身的内存块.解决问题也很简单,把append()内的数据改成dict的浅拷贝就解决了.这里用到了一个方法copy().

detail = []
for station in stations.find_all("td"):
    if station.text.strip():
        detail.append(station.text.strip())

if not detail:
    continue

for num, key in enumerate(city_station_detail):
    city_station_detail[key] = detail[num]

# 将数据填充到result
city_detail["station_detail"].append(city_station_detail.copy())

# 将result填充到results中
results.append(city_detail.copy())

问题总结

这个问题在看Python的入门课程中就有介绍了,但是时间久了就不记得了,并且自己的水平是半桶水,遇到这个问题确实有点小懵逼,最后还是在pycharm的调试器单步运行找到的原因.PyCharm真的太强大了.问题虽小,但是背后的意义确实十分重要的,Python的特性真的让人痴迷,也希望自己在以后能越来越精通吧.

参考网址:Python 直接赋值、浅拷贝和深度拷贝解析


共有 0 条评论

Top