Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Python interpreter work in dynamic typing?

I read this question, but it didn't give me a clear answer: How does Python interpreter look for types?

How does python interpreter know the type of a variable? I'm not looking how do get the type. I'm here looking at what happens behind the scene. In the example below, how does it associate the class int or string to my variable.

How does it know that is an int:

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

or that string:

>>> i = "123"
>>> type(i)
<class 'str'>
like image 585
vincedjango Avatar asked Jul 14 '16 06:07

vincedjango


People also ask

What is dynamic typed interpreter?

The term dynamic typing means that a compiler or an interpreter assigns a type to all the variables at run-time. The type of a variable is decided based on its value. The programs written using dynamic-typed languages are more flexible but will compile even if they contain errors.

Does Python use dynamic typing?

Python is a dynamically typed language. 00:12 The Python interpreter does type checking only when the code runs. As you execute a line of code, as you'll see in an example next, that's when the type checking occurs. 00:23 And also, the type of a variable is allowed to change over its lifetime.

How do dynamic typed languages work?

Implementations of dynamically type-checked languages generally associate each runtime object with a "type tag" (i.e. a reference to a type) containing its type information. This runtime type information (RTTI) can also be used to implement dynamic dispatch, late binding, downcasting, reflection, and similar features.

Why is Python a dynamic language and also a strongly typed language?

Python is strongly typed as the interpreter keeps track of all variables types. It's also very dynamic as it rarely uses what it knows to limit variable usage. In Python, it's the program's responsibility to use built-in functions like isinstance() and issubclass() to test variable types and correct usage.


2 Answers

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

Python doesn't. Variables have no type. Only the object that a variable references has a type. Variables are simply names pointing to objects.

For example, the following also shows the type of an object, but no variable is involved:

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

When you use type(variable), the variable part of the expression simply returns the object that name references, passing in the object to the type() function. When using 1 or 'foobar', the expression is a literal producing the object, which is then passed to the type() function.

Python objects are simply datastructures in the interpreter memory; in CPython C structs are used. Variables are merely references (pointers) to those structures. The basic type struct in CPython is called PyObject, and this struct has a ob_type slot that tells Python what type something is. Types are simply more C structures.

If you wanted to follow along in the CPython source code, you'd start at the 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. This function handles calls with one argument as follows:

/* 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);
    }

Here x is the PyObject object you passed in; note, not a variable, but an object! So for your 1 integer object or 'foobar' string object, the Py_TYPE() macro result is returned. Py_TYPE is a macro that simply returns the ob_type value of any PyObject struct.

So now you have the type object for either 1 or 'foobar'; how come you see <class 'int'> or <class 'str'> in your interpreter session? The Python interactive interpreter automatically uses the 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 is called which returns this:

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

So in the end, type(1) gets the ->ob_type slot, (which turns out to be the PyLong_Type struct in Python 3, long story), and that structure has a tp_name slot set to "int".

TL;DR: Python variables have no type, they are simply pointers to objects. Objects have types, and the Python interpreter will follow a series of indirect references to reach the type name to print if you are echoing the object in your interpreter.

like image 112
Martijn Pieters Avatar answered Oct 22 '22 15:10

Martijn Pieters


Python variables have no type, they are just references to objects. The size of a reference is the same regardless of what it is referring to. In the C implementation of Python it is a pointer, and does have a type, it a pointer to a Python object: PyObject *. The pointer is the same type regardless of class of object. Objects, on the other hand, know which class they belong to.

It has been argued that Python has no variables, only names, although that's a step too far for most people.

References in the CPython implementation have an id (identifier) which is actually a virtual address. The detail and value of this address is not worth pursuing - it can (and probably will) change between versions and is not meant to be used for anything other than a unique number identifying the object. Nevertheless it can provide interesting pointers (pardon the pun) to what is happening:

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

Note that the id (address) of x and y are the same - they are referencing the same object, an int with the value 42. So, what happens when we change x, does y change as well?

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

Thankfully not. Now x is just referring to a new object of class str with the value "Hello".

When we:

>>> id(y)
4297539264
>>> y = 37
>>> id(y)
4297539104 

The id of y changed! This is because it is now referencing a different object. ints are immutable, so the assignment y = 37 did not change the original object (42) it created a new one. The object with the value 42 has its reference count decremented and can now (in theory) be deleted. In practice it would probably remain in memory for efficiency reason, but thats an implementation detail.

However:

>>> a = [1,2,3,4]
>>> b = a
>>> id(a)
4324804808
>>> id(b)
4324804808
>>> a[0] = 99
>>> b
[99, 2, 3, 4]

So changing the list a has changed b! This is because lists are mutable, they can change. The assignment b = a only copied the reference, not the list. See copy in the standard library.

like image 29
cdarke Avatar answered Oct 22 '22 15:10

cdarke