[英]How does Python interpreter work in dynamic typing?
我讀了這個問題,但它沒有給我一個明確的答案: Python解釋器如何尋找類型?
python解釋器如何知道變量的類型? 我不知道如何獲得類型。 我在這里看看幕后發生了什么。 在下面的示例中,它如何將類int或string與我的變量相關聯。
它是如何知道這是一個int:
>>> i = 123
>>> type(i)
<class 'int'>
或那個字符串:
>>> i = "123"
>>> type(i)
<class 'str'>
它如何將類int或string與我的變量相關聯
Python沒有。 變量沒有類型 。 只有變量引用的對象具有類型。 變量只是指向對象的名稱 。
例如,以下內容還顯示了對象的類型,但不涉及任何變量 :
>>> type(1)
<class 'int'>
>>> type('foobar')
<class 'str'>
當使用type(variable)
,則variable
表達式的一部分簡單地返回名稱引用的對象,傳遞到物體向type()
函數。 當使用1
或'foobar'
,表達式是生成對象的文字,然后傳遞給type()
函數。
Python對象只是解釋器內存中的數據結構; 在CPython C結構中使用。 變量只是那些結構的引用(指針)。 CPython中的基本類型結構稱為PyObject
,這個結構有一個ob_type
槽 ,告訴Python什么類型的東西。 類型只是更多的C結構 。
如果你想跟隨CPython源代碼,你可以從bltinmodule.c
源碼開始(因為type
是內置名稱),它將type
定義為PyType_Type
結構 。 調用類型 ( type
也是類型 )調用它們的tp_new
函數 , PyType_Type
將其定義為type_new
函數 。 此函數使用一個參數處理調用,如下所示:
/* Special case: type(x) should return x->ob_type */
{
const Py_ssize_t nargs = PyTuple_GET_SIZE(args);
const Py_ssize_t nkwds = kwds == NULL ? 0 : PyDict_Size(kwds);
if (PyType_CheckExact(metatype) && nargs == 1 && nkwds == 0) {
PyObject *x = PyTuple_GET_ITEM(args, 0);
Py_INCREF(Py_TYPE(x));
return (PyObject *) Py_TYPE(x);
}
這里x
是你傳入的PyObject
對象; 注意,不是變量,而是對象! 因此,對於1
整數對象或'foobar'
字符串對象,將返回Py_TYPE()
宏結果。 Py_TYPE
是一個宏 , ob_type
返回任何PyObject
結構的ob_type
值。
所以現在你有1
或'foobar'
的類型對象; 你怎么在解釋器會話中看到<class 'int'>
或<class 'str'>
? Python交互式解釋器自動在任何表達式結果上使用repr()
函數 。 在C結構PyType_Type
定義中PyType_Type
結構被結合,因此所有用於該類型的時隙是直接可用; 我會在這里省略究竟是如何工作的 。 對於類型對象,使用repr()
表示調用type_repr
函數 ,該函數返回:
rtn = PyUnicode_FromFormat("<class '%s'>", type->tp_name);
所以最后, type(1)
得到->ob_type
槽,(事實證明它是Python 3中的PyLong_Type
結構 ,長篇故事),並且該結構的tp_name
槽設置為"int"
。
TL; DR :Python變量沒有類型,它們只是指向對象的指針。 對象具有類型,如果您在解釋器中回顯對象,Python解釋器將遵循一系列間接引用來到達要打印的類型名稱。
通過使用特定類的對象來“實現”變量的“類型”概念。
所以
a=float()
類型的對象float
,如由類定義float
通過返回float()
Python知道它是什么類型,因為對象是如何工作的:你知道它們是什么類型。 a
現在是一個float
對象,值為0.0。
對於內置,它是相同的,只是他們有簡短的聲明它們。
i=123
是相同的
i=int(123)
int()
返回類integer的對象,值為123。
同樣
i="123"
是相同的
i=str("123")
str("123")
返回str類的對象,值為“123”
Python變量沒有類型,它們只是對象的引用。 無論引用什么,引用的大小都是相同的。 在C Python實現它是一個指針,並確實有一個類型,它的指針到一個Python對象: PyObject *
。 無論對象類如何,指針都是相同的類型。 另一方面,對象知道它們屬於哪個類。
有人認為Python沒有變量,只有名稱,盡管對大多數人來說這是一個太過分的步驟。
CPython實現中的引用具有id(標識符),其實際上是虛擬地址。 這個地址的細節和價值不值得追求 - 它可以(並且可能會)在不同版本之間進行更改,並不意味着用於識別對象的唯一編號以外的任何其他內容。 然而,它可以提供有趣的指針(原諒雙關語)發生的事情:
>>> x = 42
>>> y = x
>>> id(x)
4297539264
>>> id(y)
4297539264
注意x
和y
的id(地址)是相同的 - 它們引用同一個對象,一個值為42的int
。那么,當我們改變x
時會發生什么, y
也會改變嗎?
>>> x = "hello"
>>> id(x)
4324832176
>>> id(y)
4297539264
謝天謝地。 現在x
只是引用類str
的新對象,其值為“Hello”。
什么時候我們:
>>> id(y)
4297539264
>>> y = 37
>>> id(y)
4297539104
y
的id改變了! 這是因為它現在引用了一個不同的對象。 int
是不可變的 ,因此賦值y = 37
沒有改變原始對象(42)它創建了一個新對象。 值為42的對象的引用計數遞減,現在(理論上)可以刪除。 在實踐中,出於效率原因,它可能會留在內存中,但這是一個實現細節。
然而:
>>> a = [1,2,3,4]
>>> b = a
>>> id(a)
4324804808
>>> id(b)
4324804808
>>> a[0] = 99
>>> b
[99, 2, 3, 4]
所以更改列表a
已經改變了b
! 這是因為列表是可變的 ,它們可以改變。 賦值b = a
只復制引用,而不是列表。 請參閱標准庫中的copy 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.