Home > Net >  assigning a method to a function attribute in Python
assigning a method to a function attribute in Python

Time:12-14

I have this two classes:

class Extraction:

    def extract(self):
        df_final = pd.DataFrame()
        
        for index in range(0, jsonPartidas.shape[0]):
            jsonPartidasIndex = json.loads(list(jsonPartidas['data'])[index])
            df_ratios = self.func(jsonPartidasIndex)
            cif, denominacion = cif_denominacion(jsonPartidasIndex)
            df_ratios['cif'] = cif
            df_ratios['denominacion'] = denominacion

            df_final = df_final.append(df_ratios)

        ratios = df_final.drop_duplicates()  
    
class Ratios(Extraction):
#     func = Ratios.find_ratio
    
    def __init__ (self, partidasRatios):
        
        self.codigos = list(partidasRatios.values())
        self.nombreColumnas = list(partidasRatios.keys())
        self.func = Ratios.find_ratio
        
    

    def find_ratio(self,jsonPartidasIndex):

        self.listaRatios = list(findkeys(jsonPartidasIndex,'listaRatios'))
        self.annosBalance = list(findkeys(jsonPartidasIndex,'annoBalance'))
        
        df_ratios = self.parseRatios()
        
        return df_ratios
    def parseRatios(self):

        self.dic_codes = {}
        self.dic_codes['anno'] = self.annosBalance
        
        self.getRatios()

        df_ratios = pd.DataFrame(self.dic_codes)
        
        return df_ratios
    def getRatios(self):
        for num, self.cod in enumerate(self.codigos):
            self.ratios = []
            self.findRatios()
            self.dic_codes[self.nombreColumnas[num]] = self.ratios   
            
    def findRatios(self):
        for ind in range(0,len(self.listaRatios)):
            ratio = self.listaRatios[ind]
            self.getValueFromRatio(ratio, ind)
                
    def getValueFromRatio(self,ratio,ind):
        for index in range(0,len(ratio)):
                dictio = list(findkeys(ratio[index],'valor'))

                if self.cod in dictio:
                    valor = [ x for x in dictio if isinstance(x, float) or isinstance(x,int)]

                    if valor:
                        self.ratios.append(valor[0])
                    else:
                        self.ratios.append(None)
                    break
                    
                
                elif index == len(ratio)-1 and len(self.ratios) < ind 1:
                    self.ratios.append(None)

I have a few classes with the method extract() that is why I create a class call Extraction that is being inherted by the other classes one of them is Ratio. I want to assign the a method that is created inside of my Ratio class call find_ratio, to the self.func so when I execute Ratios(partidasRatios).extract() (as you can see I do not want to pass any parameters to the extract method), it will run the code. I tried a lot of things and I think i got closer with the example above but I still get this error:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
C:\Users\ALVARO~1\AppData\Local\Temp/ipykernel_11044/3560029455.py in <module>
----> 1 ratios = Ratios(partidasRatios).extract()

C:\Users\ALVARO~1\AppData\Local\Temp/ipykernel_11044/1705348355.py in extract(self)
      6         for index in range(0, jsonPartidas.shape[0]):
      7             jsonPartidasIndex = json.loads(list(jsonPartidas['data'])[index])
----> 8             df_ratios = self.func(jsonPartidasIndex)
      9             cif, denominacion = cif_denominacion(jsonPartidasIndex)
     10             df_ratios['cif'] = cif

TypeError: find_ratio() missing 1 required positional argument: 'jsonPartidasIndex'

If you zoom in you can see that jsonPartidasIndex it is actually pass.

CodePudding user response:

Your find_ratio is not a class method, but a "regular" instance method. So your assignment in __init__ should look like this imho:

    self.func = self.find_ratio

No offense, but you could improve the overall design though.

You can make the whole base class abstract or at least raise an error in base class and provide implementation in the class which inherits from Extraction.

class Extraction:

    def extract(self):
        func_arg = ... # get the argument any way you want
        self.func(func_arg)

    def func(self, *args, **kwargs):
        raise NotImplementedError("Overload this with specific implementation!")

class Ratios(Extraction):
    def func(self, func_argument):
        ... # your specific implementation goes here


ratios = Ratios()
ratios.extract()

Some off-topic tips:

  • python likes snake case, be consistent with it
  • use English in your code (if you ever have to share it to non-Spanish (that's my guess what it is, sorry if it's Portuguese) speakers it will be easier to understand and all external libraries use English too, so you end up with mix of your language and English, which doesn't look good and is harder to analyze
  • use type hints, they really help
  • don't use abbreviations
  • Related