Search code examples
pythonpython-3.xpython-2.7oopgetattribute

override getattribute for instance methods and use method input variables


I have a class Titles that contains the code necessary to generate many different titles. Each title method takes in the variable rules in order to flexibly generate the correct title. There are certain formatting steps that I would like to apply regardless of which method I call. For example, rounding all floats to a single decimal place. I was trying to do this via __getattribute__, but do not know how to feed the function variables to it (i.e. rules) . Is this possible? Does __getattribute__ have access to the input variables?

Here is a quick example:

import re
class Titles:
    def __init__(self, name):
        self.name = name
    def __getattribute__(self,attr):
        res = object.__getattribute__(self, attr)() #I need to insert rules here
                                                    #somewhere into the function call
        if isinstance(res, str):
            return re.sub(
                    r'\d+\.\d{1,}', lambda m: format(float(m.group(0)), '.1f')
        return res
    def title(self, rules):
        return '{} has spent {} hours on this project'.format(self.name, rules)    

Otherwise, I guess I could have some sort of 'caller' method that would call the various methods and then format their output before returning it...


Solution

  • This sound like a decorator solution :

    import re
    class Titles:
        def __init__(self, name):
            self.name = name
        @title_decorator
        def title(self, rules):
            return '{} has spent {} hours on this project'.format(self.name, rules)
    
        @staticmethod
        @title_decorator
        def title2(rules):
            'Also works for {} staticmethods!'.format(rules)
    
    def title_decorator(func):
        def new_function(*args):
            # do something on rules
            func_result = func(*args)
            # do something on func result
            return func_result
        return new_function
    

    I wasn't sure if you wanted to format the output or input, but you could do both.