Search code examples
pythonpartialfunctools

Is there a way to transform a function to accept a callable that is evaluated just before the function?


Suppose I have a list of strings:

names = ['Alice', 'Bob', 'Charlie']

And I want to compare all of them to a specific lowercase string using some function foo:

map(lambda name: foo('carol', str.lower(name)), names)

Is there a way to alter foo to accept a callable bar that evaluates just before foo is evaluated? So I can write something like this:

map(partial(foo, 'carol', str.lower), names)  # foo sees the name in lowercase

Solution

  • That's what they made decorators for! Take a look at a decorator that lower cases all arguments pass to some function:

     def lower_args(func):
       @functools.wraps(func)
       def _wrapper(*args, **kwargs):
         l_args = map(str.lower, args)
         l_kwargs = {(name, str.lower(value)) for (name, value) in kwargs}
    
         return func(*l_args, **l_kwargs)
       return _wrapper
    

    Used like this:

    @lower_args
    def foo(a, b, c):
      #and your code goes here
    

    To do what you want, change the syntax slightly

    def to_lower(mod_func):
      def deco(func):
        @functools.wraps(func)
        def _wrapper(*args, **kwargs):
          return func(*map(mod_func, args), {(k, mod_func(v)) for (k,v) in kwargs})
        return _wrapper
      return deco
    

    Used like:

    @to_lower(my_function)
    def foo(a, b, c):
      #your code goes here