How to create a List of setters and getters in python?

2

This is how it looks in java, I have to pass it to python and I have no idea how to do it.

public List<Archivo> getArchivos() {     

   return archivos;

    }


    public void setArchivos(List<Archivo> archivos) {
        this.archivos = archivos;
    }

and I have this in python:

class ResponseUpdateDTO(object):

def set_serial(self,serial):
    self._serial = serial
@property
def get_serial(self):
    return self._serial

def set_synergy(self,value):
    self._synergy = value
@property
def get_synergy(self):
    return self._synergy


def set_responseAzure(self,value):
    self._responseAzure = value

@property
def get_responseAzure(self):
    return self._responseAzure

#falta list de archivo
    
asked by Diego Lopez 08.09.2017 в 16:00
source

3 answers

4

First of all, there is no getters or setters Java style in Python . There is no way, they do not exist. You can do something similar, yes, no doubt, but what we do will never have the philosophy of Java . There is a concept that describes well the differences in this sense between both languages, you can find it mentioned in many places, and it is the idea of the "Malicious Programmer", in Java there is a very strong encapsulation in the objects , certain properties can be accessed only through the appropriate methods, the idea is that in Java you take care of the objects of this hypothetical Bad Programmer, in Python that idea is replaced by a: "we are all adults ", that is, everyone knows what they are doing, if you want to modify an internal attribute of an object, perfect, you are supposed to know what you are doing. Please do not misinterpret this, it is simply a metaphor to describe the differences in this question and between both languages, no thing is better than the other, they are different conceptions. All this to re-emphasize "there is no getters or setters Java style in Python ", no matter how hard we put it, always but always we will have some way to access the internal attributes of an object. Having said that, let's go to your particular question:

I'm going to rewrite your code to simplify it, we define the class ResponseUpdateDTO , to have two attributes serial that in principle could be a string, and archivos , which will be a list.

class ResponseUpdateDTO(object):

    def __init__(self):
        self._serial = ""
        self._archivos = []        

    def set_serial(self, serial):
        self._serial = serial

    def get_serial(self):
        return self._serial

    def get_archivos(self):
        return self._archivos

    def set_archivos(self, archivos):
        self._archivos = archivos

Some comments:

  • It is convenient most of the time to define the method __init__ , it is not a constructor, it is simply one of the first methods that is executed when an object is instantiated and by convention it is usual to initialize here all the attributes of the object, also eventually, parameters are defined in which parameters are passed in the initialization.
  • Another convention that you have used very well is to name attributes and methods with the script under _ in front, with this we say to any other programmer: "look, these data and these functions do not use them please", in fact they are automatically removed from the documentation that you could obtain using help() , but it does not mean that they can not be used.
  • As you can see also, the pseudo getter and setter for the files does not differ from the others that you have defined.

Clearly as the code is now, you could do:

r = ResponseUpdateDTO()
r.set_archivos(['archivo1', 'archivo2'])
print(r.get_archivos())

But you can also do this:

r._archivos = ['archivo1', 'archivo2']

Clearly there is no encapsulation, you are directly accessing the attribute _archivos that we imagine private, in fact if your setter has some validation logic, it would not be running. Originally you tried to use "decorators" to get closer to the functionality you expect to see and you are indeed on the right track. Let's see how to use them and what we can really achieve:

class ResponseUpdateDTO(object):

    def __init__(self):
        self._serial = ""
        self._archivos = []        

    @property
    def serial(self):
        return self._serial

    @serial.setter
    def serial(self,serial):
        self._serial = serial

    @property
    def archivos(self):
        return self._archivos

    @archivos.setter
    def archivos(self, archivos):
        self._archivos = archivos


r = ResponseUpdateDTO()

r.archivos = ['archivo1', 'archivo2']
print(r.archivos)

What have we achieved with this?

  • First, the archivos method will behave like getter or setter depending on how we use it
  • We can incorporate logic, in particular the setter, for example to validate the data entered.

But, as I said at the beginning, there is always the possibility of doing this:

r._archivos =  ['archivo1', 'archivo2']
print(r._archivos)

But since the concept in Python is that we are all adults it should not be too big a problem, even so, there is a way to prevent doing the above, which is to name all the private variables with the double hyphen under __ , for example:

    @archivos.setter
    def archivos(self, archivos):
        self.__archivos = archivos

In this way, by doing this:

r._archivos =  ['archivo1', 'archivo2']

You will get a beautiful Exception:

  

Traceback (most recent call last): File "python", line 29, in    AttributeError: 'ResponseUpdateDTO' object has not attribute   '__files'

This is nothing more than a trick, what the interpreter does in these cases, is to "rename" the variable internally as _classname__archivos , so that you could also eventually do

r._ResponseUpdateDTO__archivos = ['archivo1', 'archivo2']
    
answered by 08.09.2017 / 18:44
source
2

As you have already commented, it is not a good idea in general to perform a literal translation from one language to another. Nothing prevents you from doing it, and you can do it as indicated by Daniel Diaz in his answer if you wish.

In Python, the concept of "setter" or "getter" does not exist as such when using Java. In your case, without validating anything in the entry or without modifying the output, the "get" and "set" methods in Python do not make sense, something like:

class MyClass(object):
    def __init__(self):
        self.archivos = []

Having an instance of the class:

>>> instancia = MyClass()

We can assign a value simply with:

>>> instancia.archivos = ['hola', 'mundo']

And get it with:

>>> instancia.archivos
['hola', 'mundo']

We can obtain and modify the attributes freely and directly, we assume that we know what we are doing, without having to sign the "forbidden access / modify, this is private" sign. The idea of getters and setters is to validate or format the output in some way and / or maintain the encapsulation of the data. For this the most appropriate and simple thing is to use the decorator @property .

Suppose that the attribute archivos must be a list of objects of a supposed class Archivo , we can use the "setter" to check the type of the input if necessary:

class Archivo(object):
    pass

class MyClass(object):
    def __init__(self):
        self._archivos = []

    @property
    def archivos(self):
        return self._archivos

    @archivos.setter
    def archivos(self, archivos):
        if isinstance(archivos, list) and all(isinstance(e, Archivo) for e in archivos):
            self._archivos = archivos
        else:
            raise ValueError('archivos debe ser una lista de instancias de Archivo')

Example of use:

  • We instanced our class:

    >>> instancia = MyClass()
    
  • We assign a list of File instances to the attribute archivos ("setter"):

    >>> instancia.archivos = [Archivo(), Archivo()]
    
  • We get the value of the attribute ("getter"):

    >>> instancia.archivos
    [<__main__.Archivo object at 0x0000018BEE9CBAC8>, <__main__.Archivo object at 0x0000018BEEA58128>]
    
  • We try to pass invalid values to the archivos attribute:

    >>> instancia.archivos = 14
    Traceback (most recent call last):
      File "<pyshell#16>", line 1, in <module>
        instancia.archivos = 14
      File ""D:\prueba.py"", line 18, in archivos
        raise ValueError('archivos debe ser una lista de instancias de Archivo')
    ValueError: archivos debe ser una lista de instancias de Archivo
    
    >>> instancia.archivos = ['Hola', "Mundo"]
    Traceback (most recent call last):
      File "<pyshell#17>", line 1, in <module>
        instancia.archivos = ['Hola', "Mundo"]
      File "D:\prueba.py", line 18, in archivos
        raise ValueError('archivos debe ser una lista de instancias de Archivo')
    ValueError: archivos debe ser una lista de instancias de Archivo
    
answered by 08.09.2017 в 18:22
1

I found an example online:

class ser_humano(object):
   def __init__(self, edad, altura, peso):
       self.__edad=edad
       self.__altura=altura
       self.__peso=peso

   def getPeso(self):
       return self.__peso

   def setPeso(self, peso = None):
       self.__peso = peso

   def getAltura(self):
       return self.__altura

   def setAltura(self, altura = None):
       self.__altura = altura

   def getEdad(self):
       return self.__edad

   def setEdad(self, edad = None):
       self.__edad = edad

Source: link

    
answered by 08.09.2017 в 16:07