Pythonic way of defining setters and getters

Question:

Searching the internet, I see that it is highly recommended not to use Setter and Getters in Python classes. However, I cannot determine a way to access private values ​​without using them. There are several recommendations about using properties, but I can't understand the advantage. Because, I don't see the possibility of determining a method for all attributes – and yet – I would have to determine a method for each – or I'm not understanding its use.

Example:

class Pessoa(object):
    def __init__(self, nome, idade, salario)
        self.__nome = nome
        self.__idade = idade
        self.__salario = salario

    def nomeGet(self):
        return self.__nome

    def nomeSet(self, nome):
        self.__nome = nome

    def idadeGet(self):
        return self.__idade

    def idadeSet(self, idade):
        self.__idade = idade

    def salarioGet(self):
        return self.__salario

    def salarioSet(self, salario):
        self.__salario = salario

I know it's not considered a good practice in Python to define so many accessor methods, however, as I mentioned before I have no idea how to avoid this, the image I have using property would be like this the same way, the difference would be to instantiate the property for each attribute. Could someone explain to me the best way to work with more than one attribute, or why it would be better to use properties?

Answer:

Let's do it by steps:

When "the whole Internet" says one thing and you don't want to do the same – who do you think is going against the grain?

In Python there is no custom of using getters and setters, because you have to think in a different way. When you say "private attributes" – are they private to "who"?

The idea of ​​encapsulation in OO is that people using your pubic class and methods don't have to worry about the private states, nor should they try to tinker with them directly. This makes it easy for you when developing the class you don't have to worry about "what if someone leaves this attribute inconsistent" between two method calls, and for those using it you don't have to worry about "if I change this value, I'll break it something in the functioning of the object"?

The purpose of private attributes IS NOT, for example, to prevent someone using your class from reading some value that you consider private for security reasons to protect yourself from something like a "malicious programmer" who is making use of your class.

Because languages ​​like Java and C++ are defined, it appears that private attributes and methods can provide security against a malicious programmer using your class. This security is not real – in both languages ​​it is possible to access these private attributes – sometimes going around a lot.

In Python and other dynamic languages, using introspection makes it pretty easy to find and use any attribute marked private (even those prefixed with __ )

In short: if someone is writing code that will run in the same process as your class with private attributes – they can and should be able to access the data. It is different from the case of a programmer on a system other than yours who will access your data through an API. In this case, the private attributes are simply not exposed in the API. In Python, instead of trying to force inaccessible private attributes, it is customary to say that the language is used by "consenting adults" .

So the practice is to prefix private attributes and methods with a single _ : that way whoever uses the class knows they don't have to mess with those attributes.

Python now has a very powerful mechanism for accessing attributes, which we call the "descriptor protocol" – this is what the property uses internally to allow you to create methods – it goes far beyond what the property allows (basically you can define attributes in a class that automatically has custom getters and setters – just create a special class for those attributes with the __get__ , __set__ or __del__ – the property does that).

That said, the property is an enabler for you, if you want to read or write an attribute, run some custom code that can transform or validate the data in that attribute, when it's accessed (for example, read the value from a database, do a formatting, validate the attribute type, etc…).

Using the property (or getters and setters) to simply store the value as it came and return it as it came doesn't make sense – unless, for example, you want the class to be thread-safe and use that code to use locks and semaphores when changing attributes. And it's because it "doesn't make sense" that the internet recommends not doing it – simply because your program will be exactly the same with or without getters and setters –

Without the property:

class Teste:
    def __init__(self, valor):
        self.valor = valor

With the property:

class Teste:
    def __init__(self, nome):
         self.nome = nome

    @property
    def nome(self):
         # Este código é executado quando alguém for
         # ler o valor de self.nome
         return self._nome

    @nome.setter
    def nome(self, value):
         # este código é executado sempre que alguém fizer 
         # self.nome = value
         self._nome = value

And presto – whoever is going to use your code, is not going to use a call to the "setter" – the magic of Python is that if you need to put custom logic in the getter and setter, it's completely transparent to whoever uses your class and its attributes. If no extra logic is needed for a given attribute, there's no point in creating a property for it.

Scroll to Top