Source From Here
Control your attributes
This tutorial will demonstrate how to simply create read-only and deletion proof attributes in your Python class. In this way, an extra layer of control can be applied to your attributes, ensuring that your class is being used as intended. While there are multiple ways to create read-only and deletion proof attributes in Python, use of the setattr and delattr dunder methods are a convenient way to quickly control the attributes in your objects.
Example: The Employee Class
To illustrate, lets envisage that we are creating a simple Employee class that requires three values to be set in the object. These values will be the employee’s name, their age, and their unique id number. These attribute values will be set in the attributes; '_name', _'age', and '_id_number' and denoted with an underscore to indicate that they are private attributes, not intended to be used outside the class.
Once the __init__ method has been set, it is necessary to define the magic method, __setattr__. In this method we can apply some simple logic to exert powerful attribute control. In the example presented, the __init__ method will call the __setattr__ method when the attributes are first set during object initialisation. We can prevent the _name attribute being reset, by applying the following logic.
To achieve, we can write a conditional that says, when a new attribute is being set, if the attribute is equal to _name and already has a value, then the program will exit and raise a built-in AttributeError exception with a custom message displayed to the standard error (stderr) output. The _name attribute is set during object initialization, so any reset to this attribute will raise the exception and terminate the program.
We could also exert some further control, by making sure that the _age and _id_number attributes are both of type integer. We can create a list and check that the _age and _id_number attributes are in that last before we set them as an integer. The code to achieve this is shown below in the setattr method.
Note: In the examples shown, when an attribute is set, it is not set using the object.attribute syntax in the setattr magic method, but rather using object.__dict__[key] = value. If we use the former approach, an endless recursive loop will be initiated, because the object.attribute syntax will call the setattr method!
Now, lets create an Employee object and check that the attributes have been set. As shown, the attributes have been set and are of the correct type:
Now, suppose, we would like to re-set the _name attribute, despite the fact it has already been set. In this case, the AttributeError exception is raised, and prints a message to the console informing the user that the name attribute has been set and cannot be re-set.
Deletion Proof Attributes
To make our name attribute deletion proof, we can simply add some logic to the under __delattr__ method. Here, we say that if the user attempts to delete the attribute name from the object, an AttributeError exception will be raised informing the user that the name attribute can not be deleted. However, we will still permit behaviour that enables users to delete any other attribute in the Employee object.
An AttributeError exception is now raised when we attempt to delete the protected name attribute from the Employee, ep object.
This tutorial will demonstrate how to simply create read-only and deletion proof attributes in your Python class. In this way, an extra layer of control can be applied to your attributes, ensuring that your class is being used as intended. While there are multiple ways to create read-only and deletion proof attributes in Python, use of the setattr and delattr dunder methods are a convenient way to quickly control the attributes in your objects.
Example: The Employee Class
To illustrate, lets envisage that we are creating a simple Employee class that requires three values to be set in the object. These values will be the employee’s name, their age, and their unique id number. These attribute values will be set in the attributes; '_name', _'age', and '_id_number' and denoted with an underscore to indicate that they are private attributes, not intended to be used outside the class.
Once the __init__ method has been set, it is necessary to define the magic method, __setattr__. In this method we can apply some simple logic to exert powerful attribute control. In the example presented, the __init__ method will call the __setattr__ method when the attributes are first set during object initialisation. We can prevent the _name attribute being reset, by applying the following logic.
To achieve, we can write a conditional that says, when a new attribute is being set, if the attribute is equal to _name and already has a value, then the program will exit and raise a built-in AttributeError exception with a custom message displayed to the standard error (stderr) output. The _name attribute is set during object initialization, so any reset to this attribute will raise the exception and terminate the program.
We could also exert some further control, by making sure that the _age and _id_number attributes are both of type integer. We can create a list and check that the _age and _id_number attributes are in that last before we set them as an integer. The code to achieve this is shown below in the setattr method.
- class Employees(object):
- def __init__(self, name, age, id_number):
- self._name = name
- self._age = age
- self._id_number = id_number
- def __setattr__(self, key, value):
- if key == '_name' and hasattr(self, '_name'):
- raise AttributeError('The value for the name attribute has already been set, and can not be re-set')
- if key in ['_age', '_id_number']:
- self.__dict__[key] = int(value)
- self.__dict__[key] = value
- def __str__(self):
- return "Employees: " + ','.join(list(map(lambda t: f"{t[0]}={t[1]}", self.__dict__.items())))
- def __repr__(self):
- return self.__str__()
Now, lets create an Employee object and check that the attributes have been set. As shown, the attributes have been set and are of the correct type:
Now, suppose, we would like to re-set the _name attribute, despite the fact it has already been set. In this case, the AttributeError exception is raised, and prints a message to the console informing the user that the name attribute has been set and cannot be re-set.
Deletion Proof Attributes
To make our name attribute deletion proof, we can simply add some logic to the under __delattr__ method. Here, we say that if the user attempts to delete the attribute name from the object, an AttributeError exception will be raised informing the user that the name attribute can not be deleted. However, we will still permit behaviour that enables users to delete any other attribute in the Employee object.
- class Employees(object):
- def __init__(self, name, age, id_number):
- self._name = name
- self._age = age
- self._id_number = id_number
- def __setattr__(self, key, value):
- if key == '_name' and hasattr(self, '_name'):
- raise AttributeError('The value for the name attribute has already been set, and can not be re-set')
- if key in ['_age', '_id_number']:
- self.__dict__[key] = int(value)
- self.__dict__[key] = value
- def __delattr__(self, key):
- if key == '_name':
- raise AttributeError('The name attribute can not be deleted')
- else:
- del self.__dict__[key]
- def __str__(self):
- return "Employees: " + ','.join(list(map(lambda t: f"{t[0]}={t[1]}", self.__dict__.items())))
- def __repr__(self):
- return self.__str__()
沒有留言:
張貼留言