
PYTHON — Python Class Internals
The question of whether a computer can think is no more interesting than the question of whether a submarine can swim. — Edsger W. Dijkstra

PYTHON — Python Scripting- Modules and Packages
Python’s class internals enable you to harness the full power of object-oriented programming. This article explores the descriptor protocol and the use of the @property and @.setter decorators to make methods behave like attributes. It also dives into the concept of __slots__ and its impact on memory usage. By the end of this tutorial, you'll have a solid understanding of how classes work behind the scenes in Python.
Let’s start with the descriptor protocol. This protocol allows you to write classes that behave like built-in types. For example, the @property and @.setter decorators are a simpler version of the descriptor protocol, and they abstract away a deeper mechanism that uses dunder methods.
Here’s an example of using the descriptor protocol to create a PositiveInteger class that ensures it can only store positive integers:
class PositiveInteger:
def __set_name__(self, owner, name):
self._name = name
def __get__(self, instance, owner):
return instance.__dict__[self._name]
def __set__(self, instance, value):
if value <= 0:
raise ValueError("Value must be positive")
instance.__dict__[self._name] = value
class Ellipse:
width = PositiveInteger()
height = PositiveInteger()
def __init__(self, width, height):
self.width = width
self.height = height
e = Ellipse(30, 40)
print(e.width) # Output: 30
print(e.height) # Output: 40In this example, PositiveInteger is a descriptor that ensures the values it stores are positive integers. When creating an Ellipse object, the width and height are assigned using the descriptor, enforcing the positive integer constraint.
Next, let’s explore __slots__. By default, the attributes of an object are stored in a dictionary named .__dict__. However, if you don't want the overhead cost of a dictionary associated with your class, you can use the special attribute .__slots__ to specify the attributes your class uses. This can save memory and improve performance.
Here’s how you can use .__slots__ to optimize memory usage:
class Point:
__slots__ = ('x', 'y')
def __init__(self, x, y):
self.x = x
self.y = yIn this example, the Point class uses .__slots__ to specify that it only needs to store x and y attributes, saving memory and improving performance.
Lastly, it’s important to note that when using descriptors and .__slots__ together, you should be cautious. Mixing descriptors and .__slots__ can lead to unexpected behavior and is generally not recommended.
In conclusion, Python’s class internals provide powerful tools and mechanisms for creating efficient and robust classes. By understanding the descriptor protocol, decorators, and .__slots__, you can take full advantage of Python's object-oriented capabilities.





