列表复制导致的BUG,以及random.choices()的问题

in #python7 years ago

近日查看程序生成的日志,发现有两个程序均出现一些重复的操作,尽管我程序中有判断,重复操作会被忽略,不会造成什么不良影响,但是有BUG总归是不好的,于是今天早晨抽出时间探究一下,看看到底是哪里出了问题。

列表复制导致的BUG

程序A很简单,把核心逻辑抽取出来大致是这样:

users = ['a', 'b', 'c', 'd']
for i in range(0, 10):
    users_copy = users
    users_copy.insert(0, 'z')
    for user in users_copy:
        print(user, " do something!")

很简单的几行代码,书写规范逻辑清晰(要脸要脸),为啥会出错呢?

Do something 啥的应该没啥错,继续简化一下代码:

users = ['a', 'b', 'c', 'd']
for i in range(0, 10):
    users_copy = users
    users_copy.insert(0, 'z')
    print(users_copy)

运行一下瞧瞧:

OMG,这是什么鬼,为何插了好多'z',之所以用user_copy,我就是想每次只更改copy的值啊。既然发现了结果的错误,就很轻易可以知道问题在哪里了。据说在 Python 语言中,一个变量保存的值除了基本类型保存的是值外,其它都是引用

所以我上述代码中:
users_copy = users
除了帮我给users起了个外号以外,并没有帮我生成一份全新的copy,亏我那么信任它,给它起了个高大山的名字。

知道了这个问题后,再改起来就简单了。

users = ['a', 'b', 'c', 'd']
for i in range(0, 10):
    users_copy = users[:]
    users_copy.insert(0, 'z')
    print(users_copy)

将代码改成上述样子,再执行一下:

这才是我想要的结果。

除了切片操作users_copy = users[:]还可以用list()函数users_copy = list(users),看起来更优雅一些?

上述修改只适合简单列表,嵌套列表等请使用copy.deepcopy(),反正对我的程序而言,这样的修改就足够了,就不再赘述了。

random.choices()的问题

搞定了程序A,我以为程序B肯定也是相同问题喽,毕竟二者的症状是一样一样的。

然而,我找了半天,我并没有进行插入之类的改变列表的操作,程序中打印了一下过程中的列表,一直没有变化,那重复是怎么产生的呢?

哎,还是老办法,简化一下逻辑,测试一下吧。

import random
users = ['a', 'b', 'c', 'd']
for i in range(0, 10):
    users_selected = random.choices(users, k=2)
    for user in users_selected:
        print(user, " do something!")

就是从一组用户中随即选择两个让他们干活!这么简单的逻辑,怎么看都没啥问题啊?

好吧,继续简化:

import random
users = ['a', 'b', 'c', 'd']
for i in range(0, 10):
    users_selected = random.choices(users, k=2)
    print(users_selected)

运行一下:

大哥,你不是在玩我吧,我让你找俩人干活,不是让你找一个人干两份活! 我吐了一口老血。

该不会是 random.choices的BUG吧,毕竟这货是Python 3.6当中新引进进来的。之前我还特意发一篇文章比较几种方式呢:
《Python 随机选取元素的一些方法以及概率问题》

想到自己发现了一个了不得的BUG,为全人类做出了贡献,那是相当兴奋啊。不过提BUG之前,先好好看看文档吧。

random.choices(population, weights=None, *, cum_weights=None, k=1)
Return a k sized list of elements chosen from the population with replacement.

等等,人家文档里只说了从列表中选择k个元素,没说不能选重复元素啊?(抗议,这是陷阱!)

random.sample(population, k)
Return a k length list of unique elements chosen from the population sequence or set.

倒是人家sample函数好好的,才是我需要的东西,当初手贱把random.sample改成了random.choices

结论

尽管两个程序表现出相同的病症,但是一个是由于我想当然的认为Python中列表赋值会生成一个副本所导致,另外一个是我想当然的认为random.choices的选择结果不会重复所导致。

想当然害死人啊。

还好我只是写点滥程序自己玩,这要是写火箭发射或者卫星轨道控制啥的,画面太美我不敢想象。不过或许这也是人家不用我写火箭发射程序的原因吧😭。

Sort:  

额,我传的动图死翘翘了

这么回事?

咋表我贊了呢?給你補這兒了~~~

哇咔咔,上当了吧,这样就可以骗到两个赞了
看在你多给我一个赞的份上,我觉得原谅你的罪行了

什麼!有這陰招?來人啊,撤讚!!

这就是《超越感觉》中说的Unwarranted Assumptions。哈哈

依然看不懂啊。。。

ThaNks FoR YoUr GooD InFo.

我最近刚开始学python给你这样一说真吓破胆

哇咔咔,是我水平不行啦,不要怕,航天飞机搞起来!

good stuff but had to use google translate

程序員真的太偉大!!!

Congratulations @oflyhigh! You have completed some achievement on Steemit and have been rewarded with new badge(s) :

You published a post every day of the week

Click on any badge to view your own Board of Honor on SteemitBoard.
For more information about SteemitBoard, click here

If you no longer want to receive notifications, reply to this comment with the word STOP

By upvoting this notification, you can help all Steemit users. Learn how here!

Good!!
Thank you:)

Coin Marketplace

STEEM 0.20
TRX 0.14
JST 0.030
BTC 64294.06
ETH 3427.66
USDT 1.00
SBD 2.59