I have the following function:
def f(x, y):
    print('x: %s' % x)
    print('y: %s' % y)
And I would like to have a wrapper like:
def g(**kwargs):
    print('hello')
    f(**kwargs)
    print('world')
Wrapper g is the function that will be returned by the decorator, so it can invoke not exactly f function but rather any function with any arguments list, so this is important to provide to function f **kwargs.
After defining g function, I would like to return g function, but with arguments list copied from f function and with the name of f function. I tried this one below:
import types
f_code = f.__code__
g_code = g.__code__
g.__code__ = types.CodeType(
    f_code.co_argcount, g_code.co_nlocals,
    g_code.co_stacksize, g_code.co_flags,
    g_code.co_code, g_code.co_consts, g_code.co_names,
    f_code.co_varnames, g_code.co_filename, f_code.co_name,
    g_code.co_firstlineno, g_code.co_lnotab,
    g_code.co_freevars, g_code.co_cellvars
)
But after calling g function I got the segmentation fault.
I googled how to solve this problem in a higher-level way, but no solutions were satisfied for me. I tried @functools.wraps, but it doesn't change arguments list, and I tried @decorator.decorator but it didn't call decorator function at all. Maybe you know better solutions for this problem?
UPDATE
Basically there is more extended example below:
funcs = {}
def h(fi, *args, **kwargs):
    def g(*args, **kwargs):
        print('hello')
        result = fi(**kwargs)
        print('world')
        return result
    funcs[fi.func_code.co_name] = g
    return g
@h
def f(x, y):
    print('%s %s' % (x, y))
    return 5
# z index is unneeded, so should be filtered
extended_arguments = {'x': 1, 'y': 2, 'z': 3}
func = funcs['f']
func_code = func.func_code
arguments = {
    i: x for i, x in extended_arguments.items()
    if x in func_code.co_varnames[:func_code.co_argcount]
}
func(**arguments)
Running this one fails with error below:
hello
Traceback (most recent call last):
  File "x.py", line 26, in <module>
    func(**arguments)
  File "x.py", line 6, in g
    result = fi(**kwargs)
TypeError: f() takes exactly 2 arguments (0 given)
This is exact case I would like to implement.
Attempt with exec:
funcs = {}
def h(fi, *args, **kwargs):
    fi_code = fi.func_code
    exec(
        '''
def g(%s*args, **kwargs):
    print('hello')
    result = fi(**kwargs)
    print('world')
    return result
        ''' % ''.join(
            '%s, ' % varname
            for varname in fi_code.co_varnames[:fi_code.co_argcount]
        )
    )
    funcs[fi_code.co_name] = g
    return g
@h
def f(x, y):
    print('%s %s' % (x, y))
    return 5
# z index is unneeded, so should be filtered
extended_arguments = {'x': 1, 'y': 2, 'z': 3}
func = funcs['f']
func_code = func.func_code
arguments = {
    i: x for i, x in extended_arguments.items()
    if i in func_code.co_varnames[:func_code.co_argcount]
}
func(**arguments)
Produces the following error:
hello
Traceback (most recent call last):
  File "y.py", line 34, in <module>
    func(**arguments)
  File "<string>", line 4, in g
NameError: global name 'fi' is not defined