1. 程式人生 > >【小思考】Python裏面有聲明和定義分離這一說麽?

【小思考】Python裏面有聲明和定義分離這一說麽?

聲明定義 告訴 符號 根據 span 如果 處理 入口 代碼

第一部分:

探究這個問題,還是因為編程的時候碰到了這個錯誤:

技術分享圖片

提示tcplink沒有定義,tcplink是我自己寫的一個給監聽到的tcp連接請求分配新線程的函數,不過是寫在了下面,就像這樣:

技術分享圖片

如果是C++裏面的話,解決這個問題很簡單。在文件開頭的時候,加上該函數的聲明式就OK,這樣不僅方便,還能最大限度的保持美觀(霧)。但是問題來了,Python裏面好像沒有聲明和定義這一說呀!

到底有沒有呢?這個得要從Python腳本的運行機制來看了。

在C++裏面,聲明是告訴編譯器我的程序裏將會有這個符號,編譯器將聲明內容進行記錄,在定義處記錄入口,分配內存。換言之,由於C++是編譯型語言,這就可以對完整的程序進行掃描,進行跨文本域的聯系。

然而,Python卻不可以,Python是解釋型語言,雖然我們自己寫的腳本是一個完整文件,但是在給Python解釋器執行的時候,依然相當於是把腳本文件裏的內容一行一行輸入進解釋器並執行。這就造成了如果執行的當前語句要調用tcplink,解釋器立馬會在之前輸入的內容中尋找tcplink的定義並執行,如果無法執行則報錯。因為有這個機制,直接就導致了不能像C/C++那樣,先放個聲明式在前面,在把定義放到其他地方。

第二部分:

有些人可能會問,拉倒吧,我編程的時候這樣寫,funcb在funcc前面,funcb內將執行funcc,為啥運行的時候什麽錯誤都不會報呢?

技術分享圖片

這就更有的說了,我們先來把這一小段放到Python命令行交互模式下,看結果如何:

技術分享圖片

對,依然也是什麽錯誤都沒發生。那麽,根據之前所說,Python解釋器是進來一行解釋一行,如果無法解釋就會立馬報錯,為什麽這裏解釋器讀入了funcc,用戶也沒有進行funcc的定義,解釋器卻沒有報錯呢?

其實,“Python解釋器是進來一行解釋一行” 這種說法其實還不太嚴謹。細心的讀者能夠發現,當在Python解釋器輸入def funcb():並回車的時候,>>>變成了...,只有在funcb用戶定義完成後並確認,才又會回到>>>。一般情況下,用戶是輸入一行回車,>>>不發生改變,並輸出應該有的結果。所以這說明了什麽呢?兩點問題:

1.在定義funcb()的時候,用戶的回車沒有讓輸入的語句執行。

2.定義完成funcb()向解釋器發送回車確認的時候,解釋器也沒有執行之前定義內的內容。(因為如果執行了,一定會報錯,就像下面這樣)

技術分享圖片

新的問題又出現了,所以之前解釋器到底執行了什麽?答案就是:執行了“定義funcb()”這一個語句。這樣,第二部分開頭的那個問題,我想大家心裏應該有答案了。把第二部分開頭的那段程序執行過程畫個圖來理解,就像這樣:

技術分享圖片

簡而言之,如果當前只是執行了“定義XXX”的語句,解釋器並不關心你具體定義的內容,此時進來的內容,解釋器暫不執行。所以由於之前的funcc()是funcb()內定義的內容,自然不執行,也就無關乎是否此時存在funcc()。但!如果我此時調用funcb,解釋器就會轉而執行funcb內的具體內容,此時如果funcc()還沒有被定義,一定會報not defined的錯誤!咱們來驗證一下:

技術分享圖片

看來,說的不錯。而第二部分開頭的代碼,在funcc實際被執行的時候,已經獲得了完整的定義,故就不會報not defined的錯誤拉~

第三部分:

那麽,有沒有什麽方法,能夠讓我的Python程序看起來更加整潔美觀——不讓所謂的“主程序”文件內函數太多而顯得雜亂呢?

其實,import是個挺不錯的方法,稍微熟悉Python的人都明白,import可以引用其他地方的py等模塊,還可以用from module import function的形式,單獨引入指定模塊內的指定函數、類。

甚至!!

技術分享圖片

對於一個從C++過來的人,真是傻了。Python的import相當於“把import的東西原封不動塞進import處一整坨”,所以由於是在函數定義內import的,所以import的東西只有在該函數內才可使用~然而C++/C的單獨#include預處理指令則是做不到的。

等等。是不是錯過了什麽重要的東西……

是的,如果import直接導入本文件,是否是可以的呢?如果可以的話,那豈不是之前的例子中,在之前加上:

from 本文件 import funca/b/c,就可以實現類似C++函數聲明的作用了?萬一成功了,那豈不是……真香?

我們來試試:

技術分享圖片

看來,真香失敗。那麽,為什麽這種方法不行呢?我們來回顧一下第二部分中部那個我自己畫的流程圖,由於Python解釋器是進來一句執行一句,所以這裏執行的內容是:導入daliywork中的funcb。執行這一句的時候,funcb沒有定義,故導入失敗。

第四部分:

最後一個問題,如果import整個文件自己本身,可不可以實現這種結果呢?(就和只執行定義XXX時解釋器不會探究具體定義的內容一樣,這種只執行導入整個文件的操作,解釋器是否會關心整個文件內的具體內容呢?)

我們再來回顧一下第三部分內關於import一個很直觀的解釋:

技術分享圖片

好了,有了這個解釋,我覺得大部分人心裏已經有答案了。測試代碼如下,我們直接執行來看一下結果:

技術分享圖片

異常棧首先提示funca沒有定義,指向daliywork第六行,但這個錯誤又是因為daliywork的第三行import導致的。這是因為import整個文件後,相當於把除了import這句以外的部分,替換到了import本身的地方,然後執行這些代碼,這時候,在引入的部分內,執行到funca,發現還是沒有進行定義,這時候再報出funca沒有進行定義的錯誤。需要註意,錯誤內報了funca沒有經過定義,並不是報的執行文件中的funca沒有定義(因為此時在源文件line3 import這一句就已經拋出異常了,程序已經停在這裏了!),而是import的daliywork裏面的第六行出現的錯誤。這一點十分重要,可以用以下的圖解進行解釋(PS:畫圖真好用):

技術分享圖片

雖然引入的內容裏,包括了所有的定義內容,但是由於引入的文件也會發生執行,所以依然無法實現我們想要的效果……

看來,由於Python特殊的解釋執行機制,導致了沒什麽方法可以只把函數的聲明提前。以後寫代碼的時候,還是乖乖要麽把定義的函數都放到其他文件通過import module方式導入,通過module.function()形式進行調用;要麽乖乖放在要執行該函數的代碼的前面吧……

無題

聲明定義要分離,Python解釋行不行?

千變萬化難模擬,繞了一圈空嘆息。

【小思考】Python裏面有聲明和定義分離這一說麽?