请猜猜下面代码的运行效果:importrandomimporttimepeople=['kingname','王小义','李小二','张小三','刘小四','陆小五','马小六','周小七','丁小八','朱小九']foriinrange(1,11):lucky_guy=random.choice(人)print(f'第{i}个抽奖,中奖用户:{lucky_guy}')time.sleep(1)你觉得这段代码运行后会不会是下图这样的结果?但实际上,我可以让输出的结果可以按照我的意愿随意改变。比如下面这个gif,所有的输出结果都是我的:大家可以别再低头看了,放下手机,自己写代码,试试gif里面的效果怎么实现。下面就为大家解密吧。要实现这个效果,只需要两个知识点:Python自带的模块可以重写。Python的导入只会在同一个运行时导入一次。我们先来看第一个知识点。Python的内置模块是可以被覆盖的,所以我们先定义一个函数:defchoice(option):return'kingname'接下来,使用这个函数来覆盖random.choice:importrandomrandom.choice=choice现在,给random什么。choice无论传入什么参数,都会返回kingname,运行效果如下图:这时候你可能会说,别人写代码的时候我重新导入random怎么办?random.choice不是又改回来了吗?是吗?其实不是,因为Python的包导入机制决定了在每个运行时内,每个包只有在第一次导入时才有效,所以只要还在当前运行时,以后所有的随机导入都是无效的。所以,即使重新导入了random模块,random.choice仍然是你修改过的代码。所以当你再次执行的时候,你会发现返回的数据还是你想要的数据,如下图:可能有人会说这样很容易被看穿,有的人随便写点测试数据就可以了首先,运行random.choice([123,456]),发现返回了kingname,这不是暴露了吗?其实完全不用担心,我们可以这样做:如果候选列表不包含kingname,那么使用原来的random.choice,如果备份的选择列表中包含kingname,则返回kingnamewith60%的概率。要实现这个功能,我们可以这样写代码:首先重启当前的Jupyter内核,将random恢复为默认,然后代码:importrandomorigin_choice=random.choicedefchoice(option):if'kingname'notinoptionorrandom.randint(1,10)>6:returnorigin_choice(option)return'kingname'random.choice=choice这个替换后,当候选列表中有kingname时,kingname会以60%的概率被选中,如下图:当kingname不在候选名单里,一切正常,如下图:转载本文请联系Code公众号。
