I have the following code which should encapsulate the x and y attributes. You must also make sure that these properties only accept values of type int or float, so that if you try to assign a value of another type to any of the properties, the TypeError exception is thrown, with the message "The type of x not what was expected" or "kind of and not what was expected", as the case may be. I was planning to implement it with a property @property decorator but I don't know how to build it The output is as expected but I don't know if it's correct
class Punto:
"""Clase Punto"""
def __init__(self, x, y):
"""Punto con sus respectivas coordenadas"""
self.x = x
self.y = y
def get_value(self):
if type(self.__x) != int and type(self.__x) != float:
raise ("el tipo de x no es el que se esperaba")
return (self.__x, self.__y)
if type(self.__y) != int and type(self.__y) != float:
raise ("el tipo de y no es el que se esperaba")
return (self.__x, self.__y)
def set_value(self, new_value):
self.__value = new_value if type(new_value) == int or type(new_value) == float else 0
value = property(get_value)
if __name__ == "__main__":
p = Punto(-8.7, 2.5)
print("(x = {}, y = {})".format(p.x, p.y))
OUTPUT: (x = -8.7, y = 2.5)
A few observations:
In the "getter" you should not validate the values, it should simply limit itself to accessing the "private" attributes and returning their value. The validation must be done in the "setter".
Currently instantiate your class with (for example):
is valid, when it shouldn't be. The problem is that you don't use the "setter" at any point to validate the arguments passed to the initializer or to validate the assignment by referring to the attribute directly (eg
p.x = 8
.First of all, clarify that encapsulation in Python, as it is understood in other languages, does not exist. Attributes are public and there is no way to make them truly private. By convention, _ is used before the identifier of an attribute/method to warn that it should be considered private and should not be modified or read directly. The use of
__
before an attribute or method does not make the attribute private either, it is just to avoid conflicts between identifiers, especially in cases of inheritance:Neither of the two mechanisms, nor the use of properties really prevents (if we really want) that supposedly private attributes can be accessed. Python by philosophy tends to treat the programmer as "of legal age", instead of prohibiting access to the attributes, the idea is to warn that they should be treated as private, but once warned, if you want to access them, you have to free to do it, we're supposed to know what we're doing... :). For this very reason the use of setter and getter as they are understood in other languages like C++ does not exist in Python.
Therefore, in Python the normal, "pythonic" way to access attributes is simply to access attributes directly. Now, if you really need something similar, it's generally appropriate to use properties, an advantage of properties is that they are accessed identically to attributes, allowing you to add extra functionality and modify it later or remove it without changing the way it works. is called, it is also more intuitive.
Going back to your code, if you want to use the decorator
@property
, you can do something like this:Which would be equivalent to, using the built-in
property()
:In both cases if you try to instantiate the class passing arguments other than
int
orfloat
(and derived classes) you get an exception:same as if you try to directly assign an invalid value to the attributes (properties):
All of this is closely related to the so-called " descriptor protocol" which, in essence, is to overlap an attribute with an object that acts as an intermediary when accessing it. Properties are a very clear example of descriptors.