Appearance
Using slots
Under normal circumstances, when we define a class and create an instance of that class, we can bind any attribute or method to the instance. This is the flexibility of dynamic languages. Let's start by defining a class:
python
class Student(object):
pass
Next, let's try binding an attribute to the instance:
python
>>> s = Student()
>>> s.name = 'Michael' # Dynamically bind an attribute to the instance
>>> print(s.name)
Michael
We can also bind a method to the instance:
python
>>> def set_age(self, age): # Define a function as an instance method
... self.age = age
...
>>> from types import MethodType
>>> s.set_age = MethodType(set_age, s) # Bind the method to the instance
>>> s.set_age(25) # Call the instance method
>>> s.age # Check the result
25
However, the method bound to one instance does not affect other instances:
python
>>> s2 = Student() # Create a new instance
>>> s2.set_age(25) # Try to call the method
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'set_age'
To bind a method to all instances, we can bind it to the class:
python
>>> def set_score(self, score):
... self.score = score
...
>>> Student.set_score = set_score
After binding the method to the class, all instances can call it:
python
>>> s.set_score(100)
>>> s.score
100
>>> s2.set_score(99)
>>> s2.score
99
In general, the set_score
method can be directly defined in the class, but dynamic binding allows us to add functionality to a class during runtime, which is difficult to achieve in static languages.
But what if we want to restrict the attributes that instances can have? For example, we only want to allow name
and age
attributes for Student
instances.
To achieve this restriction, Python allows us to define a special __slots__
variable when defining a class. This variable limits the attributes that instances of the class can add:
python
class Student(object):
__slots__ = ('name', 'age') # Use a tuple to define the allowed attribute names
Now, let's test this:
python
>>> s = Student() # Create a new instance
>>> s.name = 'Michael' # Bind the 'name' attribute
>>> s.age = 25 # Bind the 'age' attribute
>>> s.score = 99 # Bind the 'score' attribute
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'score'
Since score
is not in __slots__
, we cannot bind the score
attribute. Attempting to do so will result in an AttributeError
.
It's important to note that the attributes defined by __slots__
only affect instances of the current class and do not apply to subclasses:
python
>>> class GraduateStudent(Student):
... pass
...
>>> g = GraduateStudent()
>>> g.score = 9999
Unless __slots__
is also defined in the subclass, in which case the allowed attributes for subclass instances will be the combination of the subclass's __slots__
and the parent class's __slots__
.