0

Say, I have a general function f(input, kind) and a long list of kind. I would like to create functions f_kind(input) for each kind in the list. Instead of doing it manually by f_kind1 = partial(f, kind=kind1), is it possible to create them more dynamically via a loop over the list (something similar to setattr(class_name, method_name, method) inside a class)?

6
  • 2
    Yes, but you are probably carefully constructing something that is very very difficult for anything other than you (and possibly in the future you Yourself when you unexpectedly come back to this code in a year or more and can’t remember why on earth the code is so complicated/incomprehensible) to maintain. Commented Oct 26, 2019 at 22:37
  • Of course, have you tried using partial in a loop? Commented Oct 26, 2019 at 23:00
  • @juanpa.arrivillaga I mean, how to actually do that? I don't seem to have access to something like __dict__ inside the module itself. Commented Oct 26, 2019 at 23:07
  • You can use the globals() dict, but this is probably a bad idea Commented Oct 26, 2019 at 23:08
  • What do you mean? I meant it's a bad idea to dynamically generate these things. Commented Oct 26, 2019 at 23:11

1 Answer 1

1

Your question reminded by of an article I read long ago by Guido van Rossum about implementing multimethods in Python — because at it's core, that's what you're doing.

It would need to be adapted to work on a class, but I think it might be a better approach than using setattr() to achieve your goal.

mm.py:

''' MultiMethod module. '''

_registry = {}

class MultiMethod(object):
    def __init__(self, name):
        self.name = name
        self.typemap = {}

    def __call__(self, *args):
        types = tuple(arg.__class__ for arg in args)
        function = self.typemap.get(types)
        if function is None:
            raise TypeError("no match")
        return function(*args)

    def register(self, types, function):
        if types in self.typemap:
            raise TypeError("duplicate registration")
        print('registering: {!r} for args: {}'.format(function.__name__, types))
        self.typemap[types] = function

def multimethod(*types):
    def register(function):
        name = function.__name__
        mm = _registry.get(name)
        if mm is None:
            mm = _registry[name] = MultiMethod(name)
        mm.register(types, function)
        return mm

    return register

Sample usage.

mm_test.py:

from mm import multimethod

@multimethod(int)
def f(input):
    print('f_{}({!r}) called'.format(type(input).__name__, input))


@multimethod(str)
def f(input):
    print('f_{}({!r}) called'.format(type(input).__name__, input))

f('answer')
f(42)

@multimethod(float)
def f(input):
    print('f_{}({!r}) called'.format(type(input).__name__, input))

f(3.141529)

Output:

registering: 'f' for args: (<class 'int'>,)
registering: 'f' for args: (<class 'str'>,)
f_str('answer') called
f_int(42) called
registering: 'f' for args: (<class 'float'>,)
f_float(3.141529) called
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.