如何用 Python讓本身變整天選之子

請你們猜一猜下面這段代碼的運行效果:python

import random
import time

people = ['kingname', '王小一', '李小二', '張小三', '劉小四', '盧小五', '馬小六', '周小七', '丁小八', '朱小九']
for i in range(1, 11):
    lucky_guy = random.choice(people)
    print(f'第{i}次抽獎,中獎用戶:{lucky_guy}')
    time.sleep(1)
複製代碼

你是否是覺得這段代碼運行之後,結果以下圖所示?dom

但實際上,我可讓輸出結果根據個人意願隨意變更,例如像下面這個 gif ,全部輸出結果都是我:函數

你能夠先不要往下看,放下手機,本身寫一下代碼,試一試 如何才能實現 gif 中的效果。測試

下面來爲你們解密。編碼

要實現這個效果,只須要兩個知識點:spa

  1. Python自帶模塊是能夠被覆蓋的
  2. Python 的 import 在同一個運行時只會導入一次

首先來看第一個知識點。Python 的自帶模塊是能夠被覆蓋的,因此咱們先來定義一個函數:3d

def choice(option):
    return 'kingname'
複製代碼

接下來,使用這個函數覆蓋random.choicecode

import random
random.choice = choice
複製代碼

如今,不管給random.choice傳入什麼參數,它始終都會返回kingname,運行效果以下圖所示:cdn

這個時候,你可能會說,那別人寫代碼的時候,又從新import random怎麼辦呢?random.choice不是又被改回去了嗎?blog

實際上並不會,由於Python 的包導入機制決定了,在每一個運行時內部,每一個包只有第一次導入的時候有效,因此只要還在當前運行時,那麼後續的全部import random都是無效的。

因此,即便從新導入了 random 模塊,random.choice依然是你修改之後的代碼。因此當你再次執行的時候,會發現返回的仍是你想要的數據,以下圖所示:

可能有人會說這樣容易被識破啊,別人只要先隨便寫一些測試數據,運行一次random.choice([123, 456]),發現返回的居然是kingname,這不就露餡了嗎?

實際上徹底不用擔憂,咱們能夠這樣操做:

  1. 若是備選列表裏面不包含kingname,那麼就使用原生的 random.choice
  2. 若是備選列表裏面包含kingname,那麼就以60%的機率返回kingname

要實現這樣的功能,咱們能夠這樣寫代碼:

首先重啓當前 Jupyter 內核,讓 random 恢復成默認的,而後編碼:

import random

origin_choice = random.choice

def choice(option):
    if 'kingname' not in option or random.randint(1, 10) > 6:
        return origin_choice(option)
    return 'kingname'

random.choice = choice
複製代碼

這樣替換之後,當有kingname在備選列表中時,kingname被有60%的機率被選中,以下圖所示:

kingname不在備選列表中時,一切正常,以下圖所示:

相關文章
相關標籤/搜索