[Python]循环体中变量赋值被“覆盖”的“BUG”

0.背景

信息化老师给我布置任务来充实我颓废的寒假,遇到了这么个问题,废话也不说了,直接正题

1.问题

for program in programSpiderList
    programInfoList["start"] = program.css('td::text')[0].extract()
    programInfoList["title"] = program.css('td::text')[1].extract()
    jsonList["fhzw"].append(programInfoList)

其中 programSpiderList 是爬虫爬下来的对象,.css是其提供的一种提取内容的方法

我将两个数据填入 programInfoList 这个字典里,再append进 fhzw 这个表

奇怪的是 fhzw 这个表,将 programSpiderList 最后一条数据重复了25遍,当然这个 programSpiderList 总共也只有25条数据

如果没看明白,我把例子简化一下

endNum = []
for num in '114514'
    thenum = num + 1
    endNum.append(thenum)
print endNum

你可能以为他会打印225625,但实际上打印的是555555

当然这个例子只是为了说明问题,并不严谨

2.解释

python官方给出的答案是:

在循环结束时, thenum 的值是 5 ,所以所有的函数现在返回 5 ,即 555555 。

——Python.org(https://docs.python.org/zh-cn/3.7/faq/programming.html#id11)

其实不然,如果你有心在循环中途输出 endNum 看看,就会发现:

一开始是 2

接下来是 22

然后就变成 555

下来 6666

下来 22222

最后 555555

也就是说python并没有“实时”的去修改 endNum ,而是把 thenum 的内存地址丢给了 endNum ,如果循环的过程同时去访问 endNum ,就会收到 thenum 的实时值,循环结束后再统一保存。

3.解决办法

匿名函数、copy两种都可以

匿名函数法:

endNum = []
for num in '114514'
    thenum = num + 1
    endNum.append(lambda x=thenum: x)
print endNum

可能有朋友要问了,那x也有内存地址啊,怎么能解决呢?

但是这匿名函数,来无影去无踪,你存储的是真正的值,而不是内存地址,每一个lambda都有不同的内存,这就是“匿名”

COPY:

import copy

endNum = []
for num in '114514'
    thenum = num + 1
    endNum.append(copy.copy(thenum))
print endNum

copy本身的功能大概也是创建一个新的内存地址(ID)吧?

4.评价

python循环中靠内存地址赋值,

这好吗?这不好!

我劝这两位年轻人(匿名函数、copy)好自为之,好好反思,以后不要再犯这样的错误。

python这种设计满足了:同变量相同值的赋值需求,又提供了copy这样的方法来满足同变量动态值的复制需求,细细想,真不错!!!!!!!!

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇