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

时间:2016-07-14 06:21:19

标签: python python-internals dynamic-typing

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

python解释器如何知道变量的类型?我不知道如何获得类型。我在这里看看幕后发生了什么。在下面的示例中,它如何将类int或string与我的变量相关联。

它是如何知道这是一个int:

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

或那个字符串:

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

3 个答案:

答案 0 :(得分:10)

  

如何将类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 slot,告诉Python什么类型的东西。类型只是more C structures

如果您想在CPython源代码中进行操作,请从bltinmodule.c source code开始(因为type是内置名称),defines type as the PyType_Type structure。调用类型type也是类型)会调用tp_new functionPyType_Type defines that作为{{ 3}}。此函数使用一个参数处理调用,如下所示:

/* 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()宏结果。 the type_new function只返回任何ob_type结构的PyObject值。

现在您拥有1'foobar'的类型对象;你怎么在翻译会议上看到<class 'int'><class 'str'>? Python交互式解释器自动在任何表达式结果上使用Py_TYPE is a macro。在PyType_Type定义的C结构中,PyType_Type结构被合并,因此该类型的所有插槽都可直接使用;我在这里完全省略 的工作方式。对于类型对象,使用repr()表示调用repr() function,返回此内容:

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

最后,type(1)获取->ob_type广告位(事实证明,这是Python 3中的type_repr function,长篇故事),该结构有{{3} }}

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

答案 1 :(得分:0)

概念&#34;类型&#34;变量是&#34;实现&#34;通过使用特定类的对象。

所以在

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类的对象,值为&#34; 123&#34;

答案 2 :(得分:0)

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

有人认为Python没有变量,只有名称,尽管对于大多数人来说这是一个太过分的步骤。

CPython实现中的引用具有id(标识符),其实际上是虚拟地址。这个地址的细节和价值不值得追求 - 它可以(并且可能会)在不同版本之间进行更改,并不意味着用于识别对象的唯一编号以外的任何其他内容。然而,它可以提供有趣的指针(原谅双关语)正在发生的事情:

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

请注意xy的ID(地址)相同 - 它们引用相同的对象,int,其值为42.因此,当我们发生时会发生什么更改xy也会更改吗?

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

谢天谢地没有。现在x只是引用类str的新对象,其值为&#34; Hello&#34;。

当我们:

>>> 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