I want to create an object in python that has a few attributes and I want to protect myself from accidentally using the wrong attribute name. The code is as follows:
class MyClass( object ) : m = None # my attribute __slots__ = ( "m" ) # ensure that object has no _m etc a = MyClass() # create one a.m = "?" # here is a PROBLEM
But after running this simple code, I get a very strange error:
Traceback (most recent call last): File "test.py", line 8, in <module> a.m = "?" AttributeError: 'test' object attribute 'm' is read-only
Is there any wise programmer who can spare a bit of their time and enlighten me about "read-only" errors?
The special attribute __slots__ allows you to explicitly state which instance attributes you expect your object instances to have, with the expected results: faster attribute access.
To define a readonly property, you need to create a property with only the getter. However, it is not truly read-only because you can always access the underlying attribute and change it. The read-only properties are useful in some cases such as for computed properties. This code works perfectly fine.
slots provide a special mechanism to reduce the size of objects.It is a concept of memory optimisation on objects. As every object in Python contains a dynamic dictionary that allows adding attributes. For every instance object, we will have an instance of a dictionary that consumes more space and wastes a lot of RAM.
Why Use `__slots__`? The short answer is slots are more efficient in terms of memory space and speed of access, and a bit safer than the default Python method of data access. By default, when Python creates a new instance of a class, it creates a __dict__ attribute for the class.
When you declare instance variables using __slots__
, Python creates a descriptor object as a class variable with the same name. In your case, this descriptor is overwritten by the class variable m
that you are defining at the following line:
m = None # my attribute
Here is what you need to do: Do not define a class variable called m
, and initialize the instance variable m
in the __init__
method.
class MyClass(object): __slots__ = ("m",) def __init__(self): self.m = None a = MyClass() a.m = "?"
As a side note, tuples with single elements need a comma after the element. Both work in your code because __slots__
accepts a single string or an iterable/sequence of strings. In general, to define a tuple containing the element 1
, use (1,)
or 1,
and not (1)
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With