Home > other >  Is it correct 'pythonic' way to iterate and call instance methods?
Is it correct 'pythonic' way to iterate and call instance methods?

Time:09-28

I would like to define list of methods to be called in class variable. I would like to iterate over instance methods and call them if they are in config class variable. Is below example correct and pythonic way to do that or maybe you would advise something else?

EDIT: The purpose of it: My real class (lets call it record) takes as a init positional argument defined by me dataclass with nested dataclasses inside (which is object representation of json API response). Record class has multiple getters defined and few transformers. Finally, one method (like def consruct_useless_dict(self) to construct a record which will be inserted into SQL table. So basically config contains fields that are required in the SQL table, and each field has its own getter method (and transformer if needed)

class Foo:
    config = ['a','b','c','d']

    def __init__(self, string: str):
        self.string = string

    def a(self):
        return 'a' if 'a' in self.string else 'XXX'

    def b(self):
        return 'b' if 'b' in self.string else 'XXX'

    def c(self):
        return 'c' if 'c' in self.string else 'XXX'

    def d(self):
        return 'd' if 'd' in self.string else 'XXX'

    def construct_useless_dict(self):
        methods = [i for i in dir(self) if i in self.config]
        data = {k: getattr(self, method)() for k in self.config for method in methods if method == k}
        return data


inst = Foo('abc')
x = inst.construct_useless_dict()
print(x)
>>> {'a': 'a', 'b': 'b', 'c': 'c', 'd': 'XXX'}

CodePudding user response:

Whilst I still can't figure out the purpose of this, here's another way of doing it:-

class Foo():
    def __init__(self, s):
        self.s = s
        self.FD = {'a': self.a, 'b': self.b, 'c': self.c, 'd': self.d}

    def a(self):
        return 'a' if 'a' in self.s else 'XXX'

    def b(self):
        return 'b' if 'b' in self.s else 'XXX'

    def c(self):
        return 'c' if 'c' in self.s else 'XXX'

    def d(self):
        return 'd' if 'd' in self.s else 'XXX'

    def cud(self):
        return {k: v() for k, v in self.FD.items()}


print(Foo('abd').cud())

CodePudding user response:

Here's an alternate approach. You can automate the creation of the properties for each field in the config object using a metaclass like below:

def config_setup(what, bases=None, dict=None):
    """Metaclass which takes the same arguments as `type()`"""
    cls = type(what, bases, dict)

    def getter_for_field(f):
        return lambda self: f if f in self.string else 'XXX'

    for f in dict['config']:
        setattr(cls, f, property(getter_for_field(f)))

    return cls


class Foo(metaclass=config_setup):
    config = ['a', 'b', 'c', 'd']

    def __init__(self, string: str):
        self.string = string

    def construct_useless_dict(self):
        data = {k: getattr(self, k) for k in self.config}
        return data


foo = Foo('abc')
assert foo.d == 'XXX'

print(foo.construct_useless_dict())
print(Foo('abdc').construct_useless_dict())
  • Related