Differences between revisions 4 and 5
Revision 4 as of 2022-02-22 14:43:17
Size: 7962
Comment:
Revision 5 as of 2022-02-22 15:04:45
Size: 7334
Comment:
Deletions are marked like this. Additions are marked like this.
Line 21: Line 21:
This declaration allows us to explicitly declare data members, causes Python to reserve space for them in memory, and prevents the creation of `__dict__ ` and `__weakref__` attributes. It also prevents the creation of any variables that aren't declared in `__slots__`. The `__slots__` declaration allows us to explicitly declare data members, causes Python to reserve space for them in memory, and prevents the creation of `__dict__ ` and `__weakref__` attributes. It also prevents the creation of any variables that aren't declared in `__slots__`.
Line 24: Line 24:
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. The `__dict__` attribute is a dictionary whose keys are the variable names and whose values are the variable values. For example, here is a simple class definition: 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. The `__dict__` attribute is a dictionary whose keys are the variable names and whose values are the variable values. This allows for dynamic variable creation but can also lead to uncaught errors. For example, with the default `__dict__`, a misspelled variable name results in the creation of a new variable, but with `__slots__` it raises in an AttributeError.
Line 26: Line 26:
class Example(): class Example2():
Line 29: Line 29:
        self.var_0 = 'This is variable 0'
        self.var_1 = 'This is variable 1'
}}}
An interactive session looks like this:
{{{
>>> x = Example()
>>> print(x.__dict__.keys())
dict_keys(['var_0', 'var_1'])
        self.var_0 = "zero"
        
x2 = Example2()
x2.var0 = 0
Line 38: Line 34:
>>> print(x.__dict__.values())
dict_values(['This is variable 0', 'This is variable 1'])
}}}
We can now assign values to the variables with dot notation.
{{{
>>> x.var_0 = 'zero'
>>> x.var1 = 'one'
>>> print(x.__dict__.keys())
dict_keys(['var_0', 'var_1', 'var1'])
print(x2.__dict__.keys())
print(x2.__dict__.values())
```
Line 48: Line 38:
>>> print(x.__dict__.values())
dict_values(['zero', 'This is variable 1', 'one'])
}}}
The output here is not what was expected. The underscore was left out of the var_1 assignment and as a result we now have an extra variable in our dictionary named 'var1'. With `__slots__`, a misspelled variable name results in an Attribute Error. `__slots__` uses less memory space than `__dict__`, and direct memory access is faster than dictionary lookups. These are some of the reasons why you might want to use slots.
    dict_keys(['var_0', 'var0'])
    dict_values(['zero', 0])
Line 54: Line 42:
== Slots Basics ==
In the basic case, slots are easy to use. For example, here is a simple class definition:
{{{
class Example():
    
    __slots__ = ('_slot_0', '_slot_1')
    
    def __init__(self):
        self._slot_0 = 'This is slot 0'
        self._slot_1 = 'This is slot 1'

```python
x1.slot1 = 1
```


    ---------------------------------------------------------------------------

    AttributeError Traceback (most recent call last)

    Input In [3], in <module>
    ----> 1 x1.slot1 = 1


    AttributeError: 'Example' object has no attribute 'slot1'
Line 65: Line 58:
An interpreter session looks like this:
{{{
>>> x = Example()
>>> print(x._slot_0)
This is slot 0
Line 71: Line 59:
>>> print(x._slot_1)
This is slot 1
As mentioned earlier, a `__slots__` declaration uses less memory than a dictionary, and direct memory access is faster than dictionary lookups. `__slots__` variables use dot notation for assignment and referencing in exactly the same way as the default method. But it should be noted that attempting to access the `__slots__` tuple by subscription returns only the name of the variable.
Line 74: Line 61:
>>> x._slot_0 = 'Is _slot_1 here?'
>>> x._slot_1 = "_slot_1 is here."
>>> print(x._slot_0, "\n", x._slot_1)
Is _slot_1 here?
 _slot_1 is here.
Line 80: Line 62:
{{{python
x1.__slots__[0]
Line 81: Line 65:
That's it. To the user who is writing code, slots look and behave exactly like the default. Once we've declared and initialized our variables, we can reference and assign to them using dot notation.
    'slot_0'

Introduction

__slots__ has a mixed reputation in the Python community. On the one hand, they are considered to be popular. Lots of people like using them. Others say that they are badly understood, tricky to get right, and don't have much of an effect unless there are many instances of objects that use them. This article will explain what they are, how, and why to use them, and when not to use them.

What Is `__slots__` ?

__slots__ are discussed in the Python Language Reference under section 3.3.2, Customizing Attribute Access. The first thing we should understand is that __slots__ is only used in the context of Python classes. __slots__ is a class variable that is usually assigned a sequence of strings that are variable names used by instances. For example:

    class Example():
    __slots__ = ("slot_0", "slot_1")
    
    def __init__(self):
        self.slot_0 = "zero"
        self.slot_1 = "one"
        
x1 = Example()
print(x1.slot_0)
print(x1.slot_1)

    zero
    one

The __slots__ declaration allows us to explicitly declare data members, causes Python to reserve space for them in memory, and prevents the creation of __dict__  and __weakref__ attributes. It also prevents the creation of any variables that aren't declared in __slots__.

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. The __dict__ attribute is a dictionary whose keys are the variable names and whose values are the variable values. This allows for dynamic variable creation but can also lead to uncaught errors. For example, with the default __dict__, a misspelled variable name results in the creation of a new variable, but with __slots__ it raises in an AttributeError.

class Example2():
    
    def __init__(self):
        self.var_0 = "zero"
        
x2 = Example2()
x2.var0 = 0

print(x2.__dict__.keys())
print(x2.__dict__.values())
```

    dict_keys(['var_0', 'var0'])
    dict_values(['zero', 0])



```python
x1.slot1 = 1
```


    ---------------------------------------------------------------------------

    AttributeError                            Traceback (most recent call last)

    Input In [3], in <module>
    ----> 1 x1.slot1 = 1


    AttributeError: 'Example' object has no attribute 'slot1'

As mentioned earlier, a __slots__ declaration uses less memory than a dictionary, and direct memory access is faster than dictionary lookups. __slots__ variables use dot notation for assignment and referencing in exactly the same way as the default method. But it should be noted that attempting to access the __slots__ tuple by subscription returns only the name of the variable.

UsingSlots (last edited 2023-11-11 05:36:52 by WillHawkins)

Unable to edit the page? See the FrontPage for instructions.