Pythonic way of defining setters and getters

Asked

Viewed 14,315 times

20

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 cannot understand the advantage. For, I do not see the possibility of determining a method for all attributes - and yet - I would have to determine a method for each - or I am 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 that it is not considered a good practice in Python to define so many access methods, but as I mentioned before I have no idea how to avoid this, the image I have using property would be so in the same way, the difference would be instantiating 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?

3 answers

28


Let’s go in pieces:

When "the whole Internet" says one thing and you don’t want to do the same - who do you think is going the other way?

In Python there is no custom of using getters and setters, because you have to think differently. When you speak of "private attributes" - they are private to "who"?

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

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

Since languages such as Java and C++ are defined, it gives the impression that private attributes and methods can provide security against a malicious programmer who is using his 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, the use of introspection makes it easy to find and use any attribute marked as private (even those prefixed with __)

In short: if someone is writing code that will run in the same process as their 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 different system than yours who will access your data by an API. In this case, 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 _ : so whomever use the class knows not to mess with these attributes.

Now, Python has a mechanism much powerful for attribute access, which we call "Descriptor Protocol" - this is what is used internally by property to create methods - it goes far beyond what Property allows (basically you can define attributes in a class that automatically has getters and custom setters - just create a special class for these attributes with the methods __get__, __set__ or __del__ - the Property does this).

That said, Property is a facilitator for you, when you want to read or write an attribute, execute some custom code that can transform or validate the data of that attribute, when it is accessed (for example, read the value of a database, make a formatting, validate the type of attribute, etc...).

Using Property (or getters and setters) to simply store the value as it came and return it as it came, makes no sense - unless, for example, you want the class to be thread-safe and use that code to use Locks and semaphores in changing the attributes. And it’s by "not making sense" that the Internet recommends not to do - simply because your program will be exactly the even 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 that’s it - who’s going to use your code, is not going to use a "Setter" call - the magic of Python is that if you need to put custom logic on the getter and Setter, that’s completely transparent to whom uses its class and its attributes. If no extra logic is required for a given attribute, there is no reason to create a Property for it.

  • "...thread-safe and use this code to use Locks and semaphores in changing attributes." , very good example of a very useful thing that can be achieved in this way

  • Now it became much clearer, as it is more accessible in youtube videos Object Orientation classes in other languages, as Java for example, during learning I ended up with some addictions and I like the programming style of Python much more than java, so whenever I come across situations where in java would be done in a certain way and the Python community says to avoid before joining I want to understand why to avoid (not belittling the community of course, for sure are much more experienced than me, it is just a matter of learning). Thank you so much for your help.

  • There is a legal article about this and other customs for those who come from static languages. It is old, but it has always been a "classic" - ó "Python n~ao é Java": http://dirtsimple.org/2004/12/python-is-not-java.html

14

Exists exactly that question in so en.

If you really need setters and getters, you should use them through Property, ex:

class Pessoa(object):
    def __init__(self, nome, idade, salario):
        self._nome = nome
        self._idade = idade
        self._salario = salario

    @property
    def nome(self):
        print('get do nome')
        return self._nome

    @nome.setter
    def nome(self, nome):
        print('set do nome', nome)
        self._nome = nome

    @property
    def idade(self):
        print('get da idade')
        return self._idade

    @idade.setter
    def idade(self, idade):
        print('set da idade', idade)
        self._idade = idade

    @property
    def salario(self):
        print('get do salario')
        return self._salario

    @salario.setter
    def salario(self, salario):
        print('set do salario', salario)
        self._salario = salario


pessoa = Pessoa('Miguel', 30, 50)
print(pessoa.__dict__) # valores iniciais
pessoa.nome = 'Afonso'
pessoa.idade = 20
pessoa.salario = 500
print(pessoa.nome)
print(pessoa.idade)
print(pessoa.salario)

This is useful if you want some code to be executed (eg prints on top that are within the methods) when you do set, get, del on some property.

Looking at other research and articles written by people who know more than me, I fully agree.

...just access the attribute itself, or, if you need code to be run Every time the attribute is accessed or set, use properties.

How translated is:

...immediately access the attribute itself, or, if you need some code to be executed whenever the attribute is accessed/defined (set/get) uses properties (my example upon)

And here’s an example, given your code, of what I would do (in case I didn’t need anything extra to run on get/set/del), I try to keep it as simple as possible:

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

pessoa = Pessoa('Miguel', 30, 50)
print(pessoa.__dict__) # valores iniciais
pessoa.nome = 'Afonso'
pessoa.idade = 20
pessoa.salario = 500
print(pessoa.__dict__) # novos valores
print(pessoa.nome)
print(pessoa.idade)
print(pessoa.salario)

In this last example you might add only the methods for return, (def get_name, ...) for the sake of readability, but it is not at all necessary/convention.

"Beauty of Python’s simplicity, don’t waste it"

  • Thanks man, I’m still a little confused when the advantage of using properties instead of setters and getters, but I get the general way. Thank you. (I still have doubts about accessing private attributes.)

-2

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
print(Pessoa)        

Browser other questions tagged

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