Understanding Python Bytecode and Variable Assignment Mechanics
This article examines Python's bytecode instructions, explains how common operations like variable assignment, multiple assignment, and comparison are implemented at the interpreter level, and illustrates the underlying mechanisms with detailed code examples and disassembled bytecode.
The article explores the inner workings of Python's virtual machine by analyzing bytecode instructions and their corresponding logic, focusing on how variables are assigned and compared.
Common Bytecode Instructions
Typical operations such as loading constants, storing variables, and calling functions are demonstrated with a disassembled example:
<code>import dis
name = "古明地觉"
def foo():
age = 16
print(age)
global name
print(name)
name = "古明地恋"
dis.dis(foo)
"""
1 0 RESUME 0
2 2 LOAD_CONST 1 (16)
4 STORE_FAST 0 (age)
3 6 LOAD_GLOBAL 1 (NULL + print)
16 LOAD_FAST 0 (age)
18 CALL 1
26 POP_TOP
5 28 LOAD_GLOBAL 1 (NULL + print)
38 LOAD_GLOBAL 2 (name)
48 CALL 1
56 POP_TOP
6 58 LOAD_CONST 2 ('古明地恋')
60 STORE_GLOBAL 1 (name)
62 RETURN_CONST 0 (None)
"""
</code>The article then details each instruction, such as LOAD_CONST loading a constant and STORE_FAST creating a local variable.
Variable Assignment Details
For simple assignments like age = 16 , two bytecode instructions are generated: LOAD_CONST and STORE_FAST . More complex assignments involve additional operations.
Multiple Assignment and Swapping
The mechanics of statements like a, b = b, a are explained using the SWAP instruction:
<code>TARGET(SWAP) {
// Get top of stack
PyObject *top = stack_pointer[-1];
// oparg indicates number of elements to swap
PyObject *bottom = stack_pointer[-(2 + (oparg-2))];
assert(oparg >= 2);
// Swap elements
stack_pointer[-1] = bottom;
stack_pointer[-(2 + (oparg-2))] = top;
DISPATCH();
}
</code>For larger tuples, the interpreter builds a tuple with BUILD_TUPLE and then unpacks it using UNPACK_SEQUENCE :
<code>TARGET(BUILD_TUPLE) {
PyObject **values = (stack_pointer - oparg);
PyObject *tup = _PyTuple_FromArraySteal(values, oparg);
STACK_SHRINK(oparg);
STACK_GROW(1);
stack_pointer[-1] = tup;
DISPATCH();
}
</code>Similarly, BUILD_LIST is used when the right‑hand side is a list.
Chain Assignment
Statements like a = b = c = 123 use the COPY instruction to duplicate the top of the stack before each STORE_NAME :
<code>TARGET(COPY) {
// Get bottom element (same as top when only one element)
PyObject *bottom = stack_pointer[-(1 + (oparg-1))];
assert(oparg > 0);
PyObject *top = Py_NewRef(bottom);
STACK_GROW(1);
stack_pointer[-1] = top;
DISPATCH();
}
</code>Identity vs Equality
The difference between is and == is illustrated with the corresponding bytecode instructions IS_OP and COMPARE_OP :
<code>TARGET(IS_OP) {
PyObject *right = stack_pointer[-1];
PyObject *left = stack_pointer[-2];
int res = Py_Is(left, right) ^ oparg;
Py_DECREF(left);
Py_DECREF(right);
PyObject *b = res ? Py_True : Py_False;
STACK_SHRINK(1);
stack_pointer[-1] = b;
DISPATCH();
}
TARGET(COMPARE_OP) {
PyObject *right = stack_pointer[-1];
PyObject *left = stack_pointer[-2];
PyObject *res = PyObject_RichCompare(left, right, oparg>>4);
Py_DECREF(left);
Py_DECREF(right);
if (res == NULL) goto pop_2_error;
STACK_SHRINK(1);
stack_pointer[-1] = res;
DISPATCH();
}
</code>Examples show that a is b checks pointer equality, while a == b invokes rich comparison logic, which can be overridden by custom __eq__ methods.
Pitfalls
Chain assignment with mutable objects can cause unexpected shared references, as demonstrated with dictionaries. The article also discusses the special case of nan , where nan == nan is False, yet container membership tests treat nan as present due to identity checks.
Conclusion
The piece summarizes the examined bytecode instructions and the underlying principles of Python variable assignment, providing readers with a deeper understanding of how Python code is executed at the C level.
Python Programming Learning Circle
A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.