When should I use a Property instead of a Python attribute?

Asked

Viewed 2,537 times

6

If I set the class Person down below:

class Person:
    def __init__(self, name):
        self.__name = name

In this other way:

class Person:
    def __init__(self, name):
        self.name = name
        self.kind = kind

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self, value):
        self.__name = value

What benefit do I have? The second definition using Property, getter and Setter is not the same as the first definition using only attributes?

2 answers

11


Yes - you should use a property only - and only if - access to the attribute involves something that will be computed live, and is more practical and readable to do this with an assignment (the operator =) than calling a method.

If you won’t modify, filter, test anything in the attribute you’re using, you don’t have to create a Property.

There is a culture - which has developed in the wrong way - coming from other object-oriented languages that all access to attributes should be done by getters and setters' - and all attributes should be private.

Due to the choices and design of the Python language, where everything is open, you don’t win absolutely nothingness when creating extra getters and setters if you don’t have any relevant code within them. (As property are the pythonic way of passing by the getter and Setter keeping the access syntax to the attribute clean - no need to call a method.

So, for example, in this case, you could use properties to ensure that the name is always a string:

class Person:
    def __init__(self, name):
        self.name = name
        self.kind = kind

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        if not isinstance(value, str):
             raise TypeError("...")
        self._name = value

but even this kind of checking -s efor done on all attributes, it’s kind of lame - the idea is that the language can accept any kind of parameter that works for what it needs, and let Runtime error happen if a parameter is passed that doesn’t work. Testing an attribute like this, exceptionally it’s one thing - if you’re testing them all, it’s Review the concepts and your style. In particular, current Python allows static check of data types - so you can create your entire system with the annotations correct and use the mypy to make sure everything is okay.

Continuing - realize that one of the great advantages of properties syntax is exactly that any attribute of a class can become a code-managed attribute - that is, a Property, or other type of data - without whom use the class needs to change nothing, not even know it. That is: I can create a library that in version 1.0, the attributes "x" and "y" of a "point" class are normal instance attributes - and in version 2.0 of the same library turns them into a Property that ensures that they are always numbers - who used version 1.0 can continue using the same way with ponto.x = 10 .

This feature of Python, to access an attribute to pass through code, is not unique to properties - in fact, it is defined by the "descriptors protocol" (Descriptor Protocol), and I believe it is better documented in the document called "Data Model" language: any object that is a class attribute, and that has a name class method __get__ will be treated in a special way when accessed as attribute. A property is just a rather convenient class to build these descriptors using class-own methods to access attributes - but the mechanism is also used to couple object fields to database columns, such as in Sqlalchemy ORM or Django ORM, and by the very functions of Python, which use the descriptors mechanism so that the attribute self is automatically inserted when they are used as methods.

About attributes starting with two __: Don’t use the prefix of __ for his attributes. You gain nothing from this - this activates a language Feature of changing the real name of the attribute at compile time, to avoid name collision in subclasses - it is not something like a "private attribute". In the second decade of Python’s existence (more or less from 2000 to 2013) a lot of documentation came out - tutorials, articles and books, treating the prefix __ as if it were the equivalent of private attributes of Java and C++ - no: private attributes do not exist in the syntax or Python specifications. They exist by convention only: that is, programmers agree that attributes and methods starting with one (and only one) _ must be accessed only by the developer of a class or module, and its behavior does not need to be documented, and may be subject to changes between versions of a library or package. But this is just a convention - language does nothing to "enforce" this. On the other hand the __ activate this "name mangling" functionality - unless you know exactly what you want and what you’re doing, it’s more likely to cause a bug that’s hard to understand in your code than what you really want to happen (a clue: in 18 years developing in Python - and all kinds of advanced and absurd code, I never, not once, needed this functionality).

2

I believe that the answer is something very simple, understand, in Python, the encapsulation does not follow all the definitions as for example, the Java language, as "private", "public","protected".
But the decorators do it for us.
Behold:

class Pessoa(object):
    def __init__(self, name = "Default",idade= 10):
        self._name = name
        self._idade = idade
    
    @property
    def name(self):
        print("Metodo get foi invocado")
        return self._name
    
    
    @name.setter
    def name(self,value):
        print("Metodo set foi invocado")
        self._name = value.title()
    @property
    def idade(self):
        print("Metódo get para o atributo idade foi invocado")
        return self._idade
    @idade.setter
    def idade(self, value):
        print("Metódo set para atributo idade foi invocado")
        self._idade = value.title()

in this case, someone who uses our class, when trying to access an attribute in a 'direct' way will not be able to, unless he really wants to.
Our decorators do this for us and our functions implement the necessary logic.

That’s nice, but why use it? Well it should be used to make your code cleaner, and visually better to work, in teamwork, for example.
But think of a more specific case: when by chance we need to change the value of an attribute, and it is also in the database, changing the value in the variable will not change in our database, right? so we can implement a logic, that by changing in our class at runtime, it also changes in our database!.

  • 1

    The example of trying to synchronize the attribute with an external storage, such as the database, is very good.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.