Class return key and value of my attributes

Asked

Viewed 1,056 times

3

I have the following class:

class RegC100:
    def __init__(self,linha):
        def convFloat(valor):
            if (valor != ''):
                valor = float(valor.replace(",", "."))
                return valor
            else:
                return ''

        def convInt(valor):
            if(valor !=''):
                valor = int(valor)
                return valor
            else:
                return ''

        def convData(valor):
            if(valor != ''):
                valorDia = valor[0:2]
                valorMes = valor[2:4]
                valorAno = valor[4:8]
                valor = str(valorAno+'-'+valorMes+'-'+valorDia)
                return valor
            else:
                return ''

        self.linha = linha
        l = linha.split('|')
        self.reg = l[1]
        self.indOper = l[2]
        self.indEmit = l[3]
        self.codPart = l[4]
        self.codMod = l[5]
        self.codSit = l[6]
        self.ser = convInt(l[7])
        self.numDoc = convInt(l[8])
        self.chvNfe = l[9]
        self.dtDoc = convData(l[10])
        self.dtES = l[11]
        self.vlDoc = convFloat(l[12])
        self.indPgto = convInt(l[13])
        self.vlDesc = convFloat(l[14])
        self.vlAbatNt = convFloat(l[15])
        self.vlMerc = convFloat(l[16])
        self.indFrt = l[17]
        self.vlFrt = convFloat(l[18])
        self.vlSeg = convFloat(l[19])
        self.vlOutDa = convFloat(l[20])
        self.vlBcIcms = convFloat(l[21])
        self.vlIcms = convFloat(l[22])
        self.vlBcIcmsSt = convFloat(l[23])
        self.vlIcmsSt = convFloat(l[24])
        self.vlIpi = convFloat(l[25])
        self.vlPis = convFloat(l[26])
        self.vlCofins = convFloat(l[27])
        self.vlPisSt = convFloat(l[28])
        self.vlCofinsSt = convFloat(l[29])

receiving the following data:

|C100|0|1|99900821|55|00|2|000021255|23121207792435000327550020000212551005939150|20122012|20122012|899,00|2|||899,00|0||||0|0||||||||

I would like to make this my class return the values of my attributes as key and value or it may be an option to prepare this data to add in the database without having to type each attribute again. Is there a way? Since I am very new in this world of python I also wanted to know if there is something I can improve the code of my class. Thanks a lot for your help.

2 answers

5


A practical way is to add the method to_dict to class:

def to_dict(self):
    return self.__dict__

To get the values as key/value, simply invoke the method: obj.to_dict().

See the official documentation of __dict__ here.

See the code working here.

5

Yes - there are several ways to do this, and the wisest ones will work in conjunction with your need to assign multiple fields from a formatted line.

Of course objects in Python have the attribute __dict__, as in the other responses, which saves all attributes of the object to you. Use the __dict__directly however is not something much done in everyday life, why it does not discriminate who is who - for example, its attribute self.linha will star present at __dict__ along with the other fields.

A pretty cool mechanism to do this kind of thing is to create a base class with an access mechanism to several fields by name from a configuration of the class itself that indicates characteristics of each field.

In this case, you only need the field name, its position on the line, and conversion function. The position can be given by the order you place the fields - so you can agree for example, a class attribute fields, which is a sequence of pairs (name, conversion function), and put a method which populates and another which recovers all these values.

class Base:
    fields = [('reg', str), ('indOper', str), ..., ('vlDoc',convFloat), ...]
    def __init__(self, linha):
          self.linha = linha.split('|')

And actually, it’s more practical if this "_Fields" is a dictionary containing the information about that field. Since Python allows code execution in class creation, you can declare _Fields in the most convenient way - for example, as a single string, and create the appropriate dictionary with a function:

converters = {'float': convFloat, 'int': convInt, 'date': convDate, 'str': str }

def create_fields(spec):
     from collections import OrderedDict
     fields = OrderedDict()
     for i, field_spec in enumerate(spec.split(',')):
          field_spec = field_spec.strip()  # remove espaços em branco
          field_name, converter_name = field_spec.split()
          # em cada campo guarda sua posição e a função de conversão:
          fields[field_name] = i, converters[converter_name] 

And now you can declare each class as:

class reg100(Base):
     fields = create_fields("reg str, indOper str, ..., vlDoc float, ...")

There is also the __getattr__: is a special function that is called when Python does not find an attribute in an object - there Python calls this method by passing the attribute name. This allows the attribute name to be configured in some other way than as an explicitly valid set in hardcoded code.

    def __getattr__(self, attr):
        try:       
            field = self.fields[attr]
        except IndexError:
            raise AttributeError
        return field[1](self.linha[field[0]]

With this, and only one line per derived class (and using the function __init__ and __getattr__ declared in the base), you define all classes in your project. And now, with this information in place, you can define common methods at will to recover all fields.

For example, to have all fields converted, such as a list - and more, with the "Property" developer can make this look like a class attribute:

@property
def field_values(self):
     return [converter(self.linha[position]) for position, converter in self.fields.values()]

@property
def field_dict(self):
    return {attr_name:value[1](self.linha[value[0]) for name, value in self.fields.items()   }

Place these 4 methods in your base class, and then declare your various classes as:

class Reg100(Base):
    fields = create_fields(""reg str, indOper str, ..., vlDoc float, ...")

and go can race all the fields:

>>> r = Reg100(linha)
>>> r.reg 
(retorna o valor correspontente)
>>> r.field_values
(retorna uma lista com os valores, já convertidos para tipos Python)

Remember that as your goal is to insert everything into a relational database - you can use a ORM like Sqlalchmy to make this part easier. The ORM alone will not assign the linah valroes to class attributes, or prevent you from typing a more complex specification for each field - but you can combine the use of the ORM with Lugmas of these tips.

Browser other questions tagged

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