Python dynamic function creation with custom names

后端 未结 6 2320
深忆病人
深忆病人 2020-11-27 18:07

Apologies if this question has already been raised and answered. What I need to do is very simple in concept, but unfortunately I have not been able to find an answer for it

6条回答
  •  爱一瞬间的悲伤
    2020-11-27 18:56

    To truly create functions dynamically, you can use makefun, I have developed it just for that. It supports three ways to define the signature to generate:

    • a string representation, for example 'foo(a, b=1)'
    • a Signature object, either handcrafted or derived by using inspect.signature on another function
    • a reference function. In that case the exposed signature will be identical to this function's signature.

    Moreover you can tell it to inject the created function's reference as the first argument in your implementation, so as to have minor behavior modifications depending on where the call comes from (which facade). For example:

    # generic core implementation
    def generic_impl(f, *args, **kwargs):
        print("This is generic impl called by %s" % f.__name__)
        # here you could use f.__name__ in a if statement to determine what to do
        if f.__name__ == "func1":
            print("called from func1 !")
        return args, kwargs
    
    my_module = getmodule(generic_impl)
    
    # generate 3 facade functions with various signatures
    for f_name, f_params in [("func1", "b, *, a"),
                             ("func2", "*args, **kwargs"),
                             ("func3", "c, *, a, d=None")]:
        # the signature to generate
        f_sig = "%s(%s)" % (f_name, f_params)
    
        # create the function dynamically
        f = create_function(f_sig, generic_impl, inject_as_first_arg=True)
    
        # assign the symbol somewhere (local context, module...)
        setattr(my_module, f_name, f)
    
    # grab each function and use it
    func1 = getattr(my_module, 'func1')
    assert func1(25, a=12) == ((), dict(b=25, a=12))
    
    func2 = getattr(my_module, 'func2')
    assert func2(25, a=12) == ((25,), dict(a=12))
    
    func3 = getattr(my_module, 'func3')
    assert func3(25, a=12) == ((), dict(c=25, a=12, d=None))
    

    As you can see in the documentation, arguments are always redirected to the kwargs except when it is absolutely not possible (var-positional signatures such as in func2).

提交回复
热议问题