最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

利用一個(gè)簡(jiǎn)單的例子窺探CPython內(nèi)核的運(yùn)行機(jī)制

 更新時(shí)間:2015年03月30日 16:59:29   作者:flowerhack  
這篇文章主要介紹了利用一個(gè)簡(jiǎn)單的例子窺探CPython內(nèi)核的運(yùn)行機(jī)制,作者通過(guò)一個(gè)簡(jiǎn)單的輸出函數(shù)深入、介紹了CPython源碼C代碼中的一些函數(shù),需要的朋友可以參考下

我最近花了一些時(shí)間在探索CPython,并且我想要在這里分享我的一些冒險(xiǎn)經(jīng)歷。Allison Kaptur的excellent guide to getting started with Python internals 有一點(diǎn)啰嗦,我想逐步介紹我自己的探索過(guò)程會(huì)更加有條理性,這樣也許其他好奇的Python使用者可以跟著一起做。

1.注意到了一些奇怪的事情

一開始,我只是設(shè)置好Nose對(duì)一些我寫的Python 3代碼進(jìn)行測(cè)試。當(dāng)我運(yùn)行這些測(cè)試的時(shí)候,我得到了一個(gè)不可思議的錯(cuò)誤信息:”TypeError: bad argument type for built-in operation”,這是我之前在這個(gè)程序里沒有見到過(guò)的。

最終造成這個(gè)錯(cuò)誤的原因有一點(diǎn)顯而易見——我不小心在程序里留了一個(gè)PDB斷點(diǎn)(`import pdb; pdb.set_trace()`)。當(dāng)我把它去掉后,測(cè)試正常運(yùn)行了。

但是,我曾經(jīng)使用Nose在Python 2 repos上進(jìn)行測(cè)試,并且在那種情況下,錯(cuò)誤留下的斷點(diǎn)并不會(huì)導(dǎo)致Nose崩潰,而是看上去像是“掛起”了。程序并不是真的掛起了——它僅僅是不顯示東西到stdout(標(biāo)準(zhǔn)輸出)了。Nose是故意這樣做的,而當(dāng)我正在運(yùn)行一套測(cè)試的時(shí)候這樣做是有意義的。我可能僅僅是想看測(cè)試的結(jié)果,而不是一大堆程序自己打印出來(lái)的狀態(tài)。如果你在這個(gè)腳本里面敲擊“c”,Nose僅僅像通常那樣經(jīng)過(guò)這個(gè)斷點(diǎn)。

通常情況下,我可能只是聳聳肩,移除掉這個(gè)斷點(diǎn),然后繼續(xù)我的工作。但是!我在一個(gè)黑客學(xué)校并且有時(shí)間深入研究任何抓住我興趣的東西,所以我決定利用這次機(jī)會(huì)去窺探一下Python的內(nèi)核。

2.制造一個(gè)最簡(jiǎn)單的測(cè)試樣例。

結(jié)果這次的問(wèn)題研究起來(lái)有一點(diǎn)復(fù)雜——我并不能確定問(wèn)題是在Nose,還是PDB或者CPython自己的代碼里面。并且,我當(dāng)然不能使用任何斷點(diǎn),因?yàn)檫@些斷點(diǎn)會(huì)導(dǎo)致我的程序崩潰。

最終,在驗(yàn)證了一些假設(shè)后,看上去PDB對(duì)`input()`的調(diào)用導(dǎo)致了崩潰。所以:在Python2和Python3里面,input的實(shí)現(xiàn)有什么不同嗎?或者是其他的某些東西不同?

我和Jesse一起進(jìn)行調(diào)試,最后我們意識(shí)到Nose以一種有趣的方式處理標(biāo)準(zhǔn)輸出:
 

self._buf = StringIO()
sys.stdout = self._buf

這里用sys.stout表示Python中的所有標(biāo)準(zhǔn)輸出,即表示所有向終端輸出的內(nèi)容都會(huì)發(fā)送到這里。但由于我們可以像訪問(wèn)其他Python變量那樣訪問(wèn)sys.stout,所以我們可以改變這個(gè)sys.stout。而Nose將sys.stoud設(shè)置為StringIO(),而這只是任意一個(gè)字符串。

如果你這么做,print函數(shù)就不會(huì)工作了!
 

import sys, io
sys.stdout = io.StringIO()
print(“Hello”)
# Oh no, nothing printed!

我們懷疑是否那一行就是問(wèn)題所在,所以我們構(gòu)造了一個(gè)簡(jiǎn)單的測(cè)試樣例:
 

import sys, io
sys.stdout = io.StringIO()
print("Hello!") # Nothing will appear
input("Input: ") # Raises a TypeError

在Python 3 里面運(yùn)行這個(gè)會(huì)出現(xiàn)我們之前看到過(guò)的”bad argument for built-in operation”。所以現(xiàn)在我們知道該調(diào)查哪里了!當(dāng)你試圖改變sys.stdout的時(shí)候,內(nèi)建函數(shù)`input()`以一種奇怪的方式中斷下來(lái)。

3.了解一點(diǎn)CPython!

所以我們想要看下‘input'是怎樣實(shí)現(xiàn)的。Python有一個(gè)非常酷的模塊叫做'inspect',能讓你檢查源代碼,像這樣:
 

>>> from collections import namedtuple
>>> import inspect; print(inspect.getsource(namedtuple))
def namedtuple(typename, field_names, verbose=False, rename=False):
"""Returns a new subclass of tuple with named fields.
.....

然而當(dāng)你想要對(duì)'input'調(diào)用'inspect.getsource'的時(shí)候,結(jié)果會(huì)是:“TypeError: is not a module, class, method, function, traceback, frame, or code object.”這意味著我們的函數(shù)不是用Python實(shí)現(xiàn)的——它是用C語(yǔ)言實(shí)現(xiàn)的,因此'inspect;模塊不能為我們顯示它的代碼。

……但是,利用cinspect模塊的魔力,我們能查看C源代碼!
 

>>> import cinspect; print(cinspect.getsource(input))
static PyObject *
builtin_input(PyObject *self, PyObject *args)
{
PyObject *line;
char *str;
.....

很好,現(xiàn)在我們知道我們想要找的函數(shù)叫做'builtin_input'。這時(shí),我們將要開始瀏覽C代碼了,而不僅僅是Python代碼,我們將要在中端調(diào)試而不是在Python的解釋器里。你不需要一定是一個(gè)C語(yǔ)言專家才能看明白接下來(lái)的東西——我大多數(shù)時(shí)候會(huì)以根據(jù)函數(shù)名稱進(jìn)行推測(cè)的方式進(jìn)行。

那么,讓我們來(lái)檢索一下Cpython的  

flowerhack$ lldb -- /Users/flowerhack/cpython/python.exe
flowerhack$ breakpoint set --file bltinmodule.c --line 2337

當(dāng)單步步過(guò)源代碼的時(shí)候(這個(gè)過(guò)程和你在PDB里面做的事情很像——不停敲擊”n”來(lái)運(yùn)行下一行代碼),我們發(fā)現(xiàn)問(wèn)題第一次出現(xiàn)的那點(diǎn)代碼:
 

stdout_encoding_str = _PyUnicode_AsString(stdout_encoding);
stdout_errors_str = _PyUnicode_AsString(stdout_errors);
if (!stdout_encoding_str || !stdout_errors_str)
goto _readline_errors; // "throws" an exception

第三行誤導(dǎo)了我:“如果編碼字符串是空或者錯(cuò)誤字符串是空,那么我們會(huì)得到一個(gè)錯(cuò)誤”。但是,請(qǐng)等一下,難道一個(gè)空的錯(cuò)誤字符串不是意味著沒有錯(cuò)誤被發(fā)現(xiàn)嗎?

因?yàn)檫@個(gè),我進(jìn)一步查看了_PyUnicode_AsString的定義(另一個(gè)C函數(shù)):
 

#define _PyUnicode_AsString PyUnicode_AsUTF8

那僅僅是一個(gè)宏:“嘿,當(dāng)我們調(diào)用_PyUnicode_AsString的時(shí)候,去調(diào)用PyUnicode_AsUTF8?!彼晕覀冋嬲胍业氖荘yUnicode_AsUTF8的定義:
 

char*
PyUnicode_AsUTF8(PyObject *unicode)
{
return PyUnicode_AsUTF8AndSize(unicode, NULL);
}

……看上去這個(gè)函數(shù)所做的所有的事情是調(diào)用PyUnicode_AsUTF8AndSize,而這正是我們真正想要去閱讀的。

在PyUnicode_AsUTF8AndSize函數(shù)里面有若干個(gè)錯(cuò)誤情況,每一個(gè)都返回NULL。在錯(cuò)誤情況里面返回NULL而不是返回像-1這樣的錯(cuò)誤代碼對(duì)我來(lái)說(shuō)很奇怪。也許這里有其他我不熟悉的約定的考慮?

不管怎么樣,為了顯示出我究竟陷入了哪一個(gè)錯(cuò)誤情況,我進(jìn)行了“打印調(diào)試”——我在每一個(gè)可能的錯(cuò)誤情況后面加入了一個(gè)打印語(yǔ)句,然后運(yùn)行程序——這樣我們就能發(fā)現(xiàn)當(dāng)我們調(diào)用PyUnicode_Check到底錯(cuò)在了哪里。

那么,是否有在Python3里面進(jìn)行了而沒有在Python2里面進(jìn)行過(guò)的的檢查呢?嗯,我們能比較兩個(gè)版本的源代碼來(lái)找出這個(gè)答案。最后顯示出,Python 2 的源代碼沒有進(jìn)行類似的編碼檢查,然而Python 3做了。所以,如果sys.stdout被錯(cuò)誤編碼的東西代替了,它會(huì)在3里面運(yùn)行失敗,在2里面就不會(huì)。

4.收獲!

看上去僅僅是找出一個(gè)非常普通的固定的BUG后面的原因,就做了非常多的工作。并且也許確實(shí)是這樣。但是!我們?cè)谶@個(gè)過(guò)程中學(xué)到了一些很酷的東西。當(dāng)我在驗(yàn)證一些假設(shè)的時(shí)候我發(fā)現(xiàn)了很多Python處理標(biāo)準(zhǔn)輸入輸出的方式。我學(xué)到了更多如何閱讀大型的、很多宏的C工程的經(jīng)驗(yàn)。我學(xué)到了GOTO語(yǔ)句仍然在使用,這讓我感到很吃驚。但是在連貫性上這樣做是有意義的——看上去如果不用GOTO在C里面做一些像是異常處理的事情的時(shí)候?qū)⒆兊暮芊爆?。并且瀏覽bltinmodule.c的input 函數(shù)在Python2 和Python3中的不同真的是一件很酷的事情——嚴(yán)格上來(lái)說(shuō),是檢查。他們重構(gòu)和清理東西看上去很簡(jiǎn)潔。

聲明:設(shè)置cinspect有一點(diǎn)復(fù)雜。在這個(gè)項(xiàng)目的README里面的介紹會(huì)有一些幫助,但是注意“indexing your sources”這一步將會(huì)花很多時(shí)間。

如果你之前習(xí)慣使用gdb,那么你僅僅需要知道的是lldb和它非常相似。如果你兩個(gè)都沒有用過(guò),他們?cè)谡{(diào)試上有一點(diǎn)像PDB。

相關(guān)文章

  • PyQt5信號(hào)與槽機(jī)制案例詳解

    PyQt5信號(hào)與槽機(jī)制案例詳解

    信號(hào)和槽是一種高級(jí)接口,應(yīng)用于對(duì)象之間的通信,它是?QT?的核心特性,也是?QT?區(qū)別于其它工具包的重要地方,所有繼承qwidget的控件都支持信號(hào)與槽機(jī)制,本文給大家介紹下PyQt5信號(hào)與槽機(jī)制的相關(guān)知識(shí),感興趣的朋友一起看看吧
    2022-03-03
  • Django在admin后臺(tái)集成TinyMCE富文本編輯器的例子

    Django在admin后臺(tái)集成TinyMCE富文本編輯器的例子

    今天小編就為大家分享一篇Django在admin后臺(tái)集成TinyMCE富文本編輯器的例子,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-08-08
  • Python實(shí)現(xiàn)自定義包的實(shí)例詳解

    Python實(shí)現(xiàn)自定義包的實(shí)例詳解

    這篇文章主要介紹了實(shí)現(xiàn)自定義包的方法,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-12-12
  • django使用JWT保存用戶登錄信息

    django使用JWT保存用戶登錄信息

    這篇文章主要介紹了Django使用jwt獲取用戶信息的實(shí)現(xiàn)方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-04-04
  • 在python中實(shí)現(xiàn)同行輸入/接收多個(gè)數(shù)據(jù)的示例

    在python中實(shí)現(xiàn)同行輸入/接收多個(gè)數(shù)據(jù)的示例

    今天小編就為大家分享一篇在python中實(shí)現(xiàn)同行輸入/接收多個(gè)數(shù)據(jù)的示例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-07-07
  • 如何利用python繪制等高線圖

    如何利用python繪制等高線圖

    這篇文章主要介紹了如何利用python繪制等高線圖,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,感興趣的小伙伴可以參考一下
    2022-06-06
  • python實(shí)現(xiàn)括號(hào)匹配的多種方法小結(jié)

    python實(shí)現(xiàn)括號(hào)匹配的多種方法小結(jié)

    這篇文章主要為大家詳細(xì)介紹了python中實(shí)現(xiàn)括號(hào)匹配的三種方法,文中的示例代碼簡(jiǎn)潔易懂,具有一定的借鑒價(jià)值,有需要的小伙伴可以參考一下
    2024-12-12
  • Python爬蟲之BeautifulSoup的基本使用教程

    Python爬蟲之BeautifulSoup的基本使用教程

    Beautiful Soup提供一些簡(jiǎn)單的、python式的函數(shù)用來(lái)處理導(dǎo)航、搜索、修改分析樹等功,下面這篇文章主要給大家介紹了關(guān)于Python爬蟲之BeautifulSoup的基本使用教程,需要的朋友可以參考下
    2022-03-03
  • Python實(shí)現(xiàn)文件及文件夾操作大全

    Python實(shí)現(xiàn)文件及文件夾操作大全

    在日常工作或生活中,總避免不了需要操作文件或文件夾,本文主要介紹了Python實(shí)現(xiàn)文件及文件夾操作大全,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05
  • python里反向傳播算法詳解

    python里反向傳播算法詳解

    在本篇文章了小編給大家整理的是一篇關(guān)于python里反向傳播算法詳解內(nèi)容,有興趣的朋友們可以學(xué)習(xí)下。
    2020-11-11

最新評(píng)論

大理市| 永安市| 井研县| 哈巴河县| 申扎县| 昌平区| 岢岚县| 北辰区| 枣强县| 轮台县| 鄂州市| 哈巴河县| 桂林市| 大港区| 确山县| 凯里市| 平度市| 久治县| 家居| 松溪县| 花莲市| 康保县| 徐州市| 盘山县| 吴桥县| 龙游县| 嘉荫县| 兴隆县| 洪雅县| 宁津县| 张家口市| 乌苏市| 阿坝| 双桥区| 涟源市| 远安县| 长治县| 德昌县| 江陵县| 台南县| 上杭县|