Python 解释器如何在动态类型中工作?

How does Python interpreter work in dynamic typing?

我看了这个问题,但没有给我一个明确的答案: How does Python interpreter look for types?

python解释器如何知道变量的类型?我不是在看如何获得类型。我在这里查看幕后发生的事情。在下面的示例中,它如何将 class int 或 string 关联到我的变量。

它怎么知道那是一个整数:

>>> i = 123
>>> type(i) 
<class 'int'>

或那个字符串:

>>> i = "123"
>>> type(i)
<class 'str'>

变量的概念"type"是"implemented"通过使用特定class的对象。

所以在

a=float()

float 类型的对象,由 class float 定义,由 float() 返回。 Python 知道它是什么类型,因为这就是对象的工作方式:您知道它们是什么类型。 a 现在是一个 float 对象,值为 0.0.

内置函数也是一样的,只是它们有声明它们的简写形式。

i=123

相同

i=int(123)

int() returns 一个 class 整数对象,值为 123。

同样

i="123"

相同

i=str("123")

str("123") returns class str 的对象,值为“123”

how does it associate the class int or string to my variable

Python 没有。 变量没有类型。只有变量引用的对象才有类型。变量只是 指向对象的名称 .

例如下面也显示了一个对象的类型,但是没有涉及变量:

>>> type(1)
<class 'int'>
>>> type('foobar')
<class 'str'>

当您使用 type(variable) 时,表达式的 variable 部分只是 returns name 引用的对象,传入 objecttype() 函数。当使用 1'foobar' 时,表达式是生成对象的文字,然后传递给 type() 函数。

Python 对象只是解释器内存中的数据结构;在 CPython 中使用 C 结构。变量只是对这些结构的引用(指针)。 CPython 中的基本类型结构称为 PyObject, and this struct has a ob_type slot that tells Python what type something is. Types are simply more C structures.

如果您想继续学习 CPython 源代码,可以从 bltinmodule.c source code (since type is a built-in name), which defines type as the PyType_Type structure. Calling a type (type is a type too) invokes their tp_new function, and PyType_Type defines that as the type_new function 开始。此函数处理带有 one 参数的调用,如下所示:

/* 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 is a macro 简单地 returns 任何 PyObject 结构的 ob_type 值。

所以现在你有了 1'foobar' 的类型对象;你怎么会在口译会话中看到 <class 'int'><class 'str'>? Python 交互式解释器自动使用 repr() function on any expression results. In the C structure for PyType_Type definitions the PyType_Type struct is incorporated so all the slots for that type are directly available; I'll omit here exactly how that works. For type objects, using repr() means the type_repr function 调用 which returns this:

rtn = PyUnicode_FromFormat("<class '%s'>", type->tp_name);

所以最后,type(1) 得到了 ->ob_type 插槽,(原来是 PyLong_Type struct in Python 3, long story), and that structure has a tp_name slot set to "int".

TL;DR: Python 变量没有类型,它们只是指向对象的指针。 对象 有类型,如果您在解释器中回显对象,Python 解释器将遵循一系列间接引用以达到要打印的类型名称。

Python 变量没有类型,它们只是对对象的引用。无论引用的是什么,引用的大小都是相同的。在 Python 的 C 实现中它是一个指针,而 有一个类型,它是一个指向 Python 对象的指针:PyObject *。不管对象的 class 是什么,指针都是相同的类型。另一方面,对象知道它们属于哪个class。

有人认为 Python 没有变量,只有名称,尽管这对大多数人来说太过分了。

CPython 实现中的引用有一个 id(标识符),它实际上是一个虚拟地址。这个地址的细节和价值不值得追求 - 它可以(并且可能会)在不同版本之间发生变化,并且除了标识对象的唯一编号外,不打算用于任何其他用途。然而,它可以为正在发生的事情提供有趣的指示(请原谅双关语):

>>> x = 42
>>> y = x
>>> id(x)
4297539264
>>> id(y)
4297539264

请注意 xy 的 id(地址)是相同的——它们引用同一个对象,一个值为 42 的 int。那么,会发生什么当我们改变 x 时,y 也会改变吗?

>>> x = "hello"
>>> id(x)
4324832176
>>> id(y)
4297539264

谢天谢地没有。现在 x 只是引用 class 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