小新:神奇痘绎,沒想到解釋器都執(zhí)行到后面了,還能往前跳蛉幸。
小Co:那是破讨,解釋器會主動去尋找這個函數(shù)名的定義所在的位置,所以函數(shù)定義在文件里的位置不是特別重要奕纫。我們接著看到43行提陶,這里是表示把r設(shè)為空的字典,字典在上文也提到過匹层,是python里的一種數(shù)據(jù)結(jié)構(gòu)隙笆,這里用來存放獎券號以及對應(yīng)的分?jǐn)?shù)。44行又調(diào)用了通過hash值計算幸運(yùn)數(shù)的函數(shù)升筏。
小新:誒撑柔?函數(shù)里又調(diào)用了一個新函數(shù),那這下解釋器是按照什么順序來執(zhí)行的呢您访?
小Co:按照上面說過的函數(shù)調(diào)用的順序铅忿,即解釋器會跳轉(zhuǎn)到計算幸運(yùn)數(shù)函數(shù)的定義里,全部執(zhí)行完灵汪,再跳回計算得分的函數(shù)檀训,繼續(xù)從46行執(zhí)行下去。如果按照解釋器的步驟识虚,我們現(xiàn)在應(yīng)該跳到新函數(shù)里肢扯,看它是怎么生成幸運(yùn)數(shù)的,但是為了完整的了解一個函數(shù)的過程担锤,確保思路不被打斷蔚晨,我們在了解新函數(shù)大致作用的前提下,可以先不去看新函數(shù)的具體實現(xiàn),而是繼續(xù)把本函數(shù)看完铭腕,之后再跳去新函數(shù)银择。
小新:嗯嗯,我也覺得這樣更好累舷,如果先去看計算幸運(yùn)數(shù)函數(shù)浩考,再回來繼續(xù)看計算得分函數(shù)剩下的部分,我打賭我會頭暈被盈。析孽。
小Co:哈哈,是的只怎,這里還好只有一兩個新函數(shù)袜瞬,如果是很多個的話,你很容易就迷失自我了身堡,甚至?xí)岩扇松擞取!?/p>
接下來贴谎,46到48行是一個for循環(huán)汞扎,range(1, total_lottery + 1)的意思是生成一個1到total_lottery(上文提到的總票數(shù))的序列。for lottery_id in表示每次循環(huán)lottery_id依次設(shè)置為序列里的值擅这,即從1澈魄,2,3仲翎,一忱。。谭确。依次設(shè)置到total_lottery,代表的含義就是獎券號票渠。
47行是調(diào)用了計算每張獎券得分的函數(shù)逐哈,注意到這個函數(shù)的輸入?yún)?shù)包括了上面算出來的幸運(yùn)數(shù),和每次循環(huán)的獎券號lottery_id问顷。48行是把獎券號和對應(yīng)的分?jǐn)?shù)放到r這個字典里昂秃。當(dāng)循環(huán)結(jié)束后,返回獎券得分結(jié)果r杜窄。
幸運(yùn)數(shù)
小Co:上面的計算獎券得分的函數(shù)流程看完后肠骆,我們再回過頭看看計算幸運(yùn)數(shù)的流程。這個函數(shù)的主要思路就是用不同hash算法進(jìn)行多次計算塞耕,最后得到一個只能由輸入值唯一確定的幸運(yùn)數(shù)蚀腿。
注意這里輸入的h就是上文的比特幣區(qū)塊哈希值。15行定義了一個列表hash_names,里面包括了常見的各種hash算法莉钙,其中在比特幣里常用的有RIPEMD160和sha256廓脆。
16行是print打印語句。18行的repeat設(shè)置成了8百萬磁玉,這個數(shù)表示要對反復(fù)對各hash算法進(jìn)行8百萬次循環(huán)計算停忿。
小新:我的天,8百萬次蚊伞,這是個什么概念啊席赂,感覺一次hash計算就好復(fù)雜的樣子,就算是計算機(jī)时迫,這么多次豈不是也要算到郝#枯石爛?
小Co:是的别垮,我之前試了一次便监,整個算法程序運(yùn)行了20多分鐘才計算完,其中絕大部分時間都花在了這個函數(shù)里碳想。其實只是為了生成個隨機(jī)數(shù)的話烧董,8次循環(huán)也就夠了。官方設(shè)置成這么大胧奔,可能也是小小的皮了一下吧逊移,哈哈。
19行把變量r設(shè)置成了輸入的h龙填,也就是比特幣區(qū)塊的哈希值胳泉,在之后的計算中,h就沒用了岩遗,全是針對r了扇商。20行就用到了8百萬這個值,表示21到26行會執(zhí)行8百萬次宿礁,那我們下面就看看某一次循環(huán)會發(fā)生什么案铺。
21行判斷,如果(if)當(dāng)前次數(shù)能夠除以100000的余數(shù)是0梆靖,就打印一句話控汉。Emmm,好吧返吻,這個打印也沒什么用姑子。
23行的for循環(huán)表示依次取出列表hash_names里的hash算法。
小新:等等测僵,這里又來了一個for循環(huán)啊街佑,外面不是已經(jīng)有了一個for了嗎?
小Co:和函數(shù)一樣,for也是可以嵌套使用的舆乔。記住岳服,里面的for循環(huán)全部執(zhí)行完了之后,才會執(zhí)行外面for的下一次循環(huán)希俩。
24到26行是使用了上文提過的hashlib庫吊宋,new(n)是根據(jù)n表示hash算法,生成一個對應(yīng)算法的對象颜武,update(r)是使用該算法璃搜,生成r對應(yīng)的計算結(jié)果hash值,digest()是把hash結(jié)果用16進(jìn)制表示鳞上,賦給r这吻。
小新:感覺這里有點難篙议。唾糯。對象什么的,完全沒概念鬼贱。而且你不是說h沒用了嗎移怯,這里怎么又出現(xiàn)了。
小Co:確實这难,這里完全理解對于新手來說比較困難舟误,但是你現(xiàn)在只要知道這三個步驟所代表的含義就可以了。上面h代表的區(qū)塊哈希值確實沒用了姻乓,這里出現(xiàn)的h只是起到一個臨時變量的作用嵌溢,如果把for里面出現(xiàn)的h全部換成k,效果是一樣的蹋岩,也不會有迷惑性了赖草。
最后,我們可以看到剪个,一次for計算的hash結(jié)果值賦給了r疚顷,在下一次for循環(huán)中,r又是作為了hash計算的輸入值禁偎,就這樣來來回回的計算,最后函數(shù)返回的幸運(yùn)數(shù)完全不是人力能夠計算出來的阀坏,保證了結(jié)果的公平性如暖。
小新:嗯嗯,肯定是公平的了忌堂。那隨機(jī)性呢盒至?相同的比特幣hash值輸入下,每次運(yùn)行這個函數(shù)的結(jié)果是一樣的嗎?
小Co:沒有隨機(jī)性枷遂,每次的結(jié)果都是一樣的樱衷。相同輸入下,不管什么類型的hash算法酒唉,只要是相同的算法類型矩桂,其結(jié)果都是相同的。