Skip to content

Effortlessly Understanding Pointers in Python

CodeMDD.io

Pointers in Python: What’s the Point?

If you’ve ever worked with lower level languages like C or C++, then you’ve probably heard of pointers. Pointers allow you to create great efficiency in parts of your code. They also cause confusion for beginners and can lead to various memory management bugs, even for experts. So where are they in Python, and how can you simulate pointers in Python?

Pointers are widely used in C and C++. Essentially, they are variables that hold the memory address of another variable. For a refresher on pointers, you might consider checking out this overview on C Pointers.

In this article, you’ll gain a better understanding of Python’s object model and learn why pointers in Python don’t really exist. For the cases where you need to mimic pointer behavior, you’ll learn ways to simulate pointers in Python without the memory-management nightmare.

In this article, you ‘ll:

  • Learn why pointers in Python don’t exist
  • Explore the difference between C variables and Python names
  • Simulate pointers in Python
  • Experiment with real pointers using ctypes

Note: In this article, “Python” will refer to the reference implementation of Python in C, otherwise known as CPython. As the article discusses some internals of the language, these notes are true for CPython 3.7 but may not be true in future or past iterations of the language.

Why Doesn’t Python Have Pointers?

The truth is that I don’t know. Could pointers in Python exist natively? Probably, but pointers seem to go against the Zen of Python. Pointers encourage implicit changes rather than explicit. Often, they are complex instead of simple, especially for beginners. Even worse, they beg for ways to shoot yourself in the foot, or do something really dangerous like read from a section of memory you were not supposed to.

Python tends to try to abstract away implementation details like memory addresses from its users. Python often focuses on usability instead of speed. As a result, pointers in Python don’t really make sense. Not to fear though, Python does, by default, give you some of the benefits of using pointers.

Understanding pointers in Python requires a short detour into Python’s implementation details. Specifically, you’ll need to understand:

  1. Immutable vs mutable objects
  2. Python variableshttps://codemdd.io/names

Hold onto your memory addresses, and let’s get started.

Objects in Python

In Python, everything is an object. For proof, you can open up a REPL and explore using isinstance():

>>> isinstance(1, object)
True
>>> isinstance(list(), object)
True
>>> isinstance(True, object)
True
>>> def foo():
... pass
...
>>> isinstance(foo, object)
True

This code shows you that every value in Python is an instance of the object class. The object class is the root parent of all classes in Python, so everything is derived from it. This means that everything you create in Python, including variables, functions, and data structures, are objects.

Immutable vs Mutable Objects

In Python, objects can be categorized into two main types: immutable and mutable objects. Understanding the distinction between these two types is crucial for understanding how pointers work in Python.

Immutable Objects: Immutable objects are objects whose value cannot be changed after they are created. Examples of immutable objects in Python include numbers, strings, and tuples. Once an immutable object is created, any operation that seems to modify it actually creates a new object with the updated value.

Mutable Objects: Mutable objects, on the other hand, are objects whose value can be changed after they are created. Examples of mutable objects in Python include lists, dictionaries, and sets. You can modify the value of a mutable object without creating a new object.

Understanding Variables

To further explore how pointers work in Python, it’s important to understand the difference between variables in C and names in Python.

Variables in C: In C, variables are memory locations with a defined type and a name. When you create a variable in C, you allocate memory for that variable, and the variable’s name refers to the memory location where the value is stored. Pointers in C hold the memory address of another variable.

Names in Python: In Python, names are references to objects. When you create a name in Python, you are binding that name to an object. Names in Python do not directly refer to memory locations like variables in C. Instead, they refer to objects, and these objects are automatically managed by Python’s memory management system.

A Note on Intern Objects in Python: Python has a concept called interned objects, which are objects that have a single, unique copy that is shared between different names. This means that names can refer to the same interned object. This behavior may seem similar to pointers, but it operates at a higher level of abstraction.

Simulating Pointers in Python

Although Python does not have native pointers like C or C++, you can simulate pointer behavior in Python using different techniques. Here are two common approaches:

1. Using Mutable Types as Pointers: One way to simulate pointers in Python is by using certain mutable types, such as lists or dictionaries, as “pointers” to other objects. By modifying the value at a specific index in a list or the value associated with a specific key in a dictionary, you can achieve similar behavior to pointers in C.

# Simulating a pointer in Python using a list
pointer = [0] # The list will hold the memory address of other objects
value = 5
pointer[0] = value
print(pointer[0]) # Output: 5
value = 10
print(pointer[0]) # Output: 10

2. Using Python Objects: Another way to simulate pointers in Python is by using Python objects. By creating custom classes and defining methods to manipulate the state of an object, you can control the behavior and achieve pointer-like behavior.

class Pointer:
def __init__(self):
self.value = None
def set_value(self, value):
self.value = value
def get_value(self):
return self.value
pointer = Pointer()
value = 5
pointer.set_value(value)
print(pointer.get_value()) # Output: 5
value = 10
print(pointer.get_value()) # Output: 10

These techniques allow you to simulate pointer behavior in Python, but it’s important to remember that they are not true pointers. They are simply ways to achieve similar behavior by manipulating mutable objects or custom classes.

Real Pointers With ctypes

If you need to work with real pointers in Python, you can use the ctypes module. ctypes allows you to create and manipulate C-compatible data types in Python. You can allocate memory, read and write values to memory addresses, and even call functions from shared libraries.

Here’s a simple example that demonstrates how to use ctypes to work with pointers in Python:

import ctypes
# Define a C-compatible data structure
class Data(ctypes.Structure):
_fields_ = [("x", ctypes.c_int)]
# Create an instance of the data structure
data = Data()
data.x = 5
# Access the memory address of the data structure
address = ctypes.addressof(data)
print(address) # Output: 140196305025024
# Create a pointer to the data structure
pointer = ctypes.pointer(data)
# Access the value through the pointer
print(pointer.contents.x) # Output: 5
# Modify the value through the pointer
pointer.contents.x = 10
print(data.x) # Output: 10

In this example, ctypes is used to define a C-compatible data structure and create an instance of that structure. The memory address of the structure is accessed using ctypes.addressof(), and a pointer to the structure is created using ctypes.pointer(). The value of the structure can be accessed and modified through the pointer.

Conclusion

Although Python does not have native pointers like C or C++, you can simulate pointer behavior using different techniques. By understanding the object model of Python and how variableshttps://codemdd.io/names work, you can gain a better understanding of why pointers don’t really exist in Python. The techniques discussed in this article, such as using mutable types as pointers and creating custom classes, allow you to achieve similar behavior to pointers. Additionally, the ctypes module provides a way to work with real pointers in Python if necessary. Remember, simulating pointers in Python requires careful consideration and understanding of the underlying concepts to avoid potential pitfalls and memory-management issues.