python-FunctionType动态创建函数,并自定义函数名称(动态生成测试用例)

方法一

  但无法编写foo函数体里面内容

import types

def foo(x,y):
    #print(x,y)
    return 1

x = 1
y = 2
f = types.FunctionType(foo.__code__, {}, name='test_',argdefs=(x,y))
print(f.__name__)
print(f(1,2))

 

方法2

from utils.create_function import create_function_from_parameters
from inspect import Parameter, Signature

def foo(arg):
    print(arg)
    return 1


x = 1
y = 2
f = create_function_from_parameters(
            func=foo,
            parameters=[Parameter('x', Parameter.POSITIONAL_OR_KEYWORD),
                        Parameter('y', Parameter.POSITIONAL_OR_KEYWORD),
                        ],
            documentation="some doc",
            func_name="test_",
            func_filename="main.py",
        )
print(f.__name__)
print(f(x,y))

 

import sys
import types
from typing import Any, Callable, Mapping, Sequence
from inspect import Parameter, Signature


def create_function_from_parameters(
        func: Callable[[Mapping[str, Any]], Any],
        parameters: Sequence[Parameter],
        documentation=None,
        func_name=None,
        func_filename=None):
    new_signature = Signature(parameters)  # Checks the parameter consistency

    def pass_locals():
        return dict_func(locals())  # noqa: F821 TODO

    code = pass_locals.__code__
    mod_co_argcount = len(parameters)
    mod_co_nlocals = len(parameters)
    mod_co_varnames = tuple(param.name for param in parameters)
    mod_co_name = func_name or code.co_name
    if func_filename:
        mod_co_filename = func_filename
        mod_co_firstlineno = 1
    else:
        mod_co_filename = code.co_filename
        mod_co_firstlineno = code.co_firstlineno

    if sys.version_info >= (3, 8):
        modified_code = code.replace(
            co_argcount=mod_co_argcount,
            co_nlocals=mod_co_nlocals,
            co_varnames=mod_co_varnames,
            co_filename=mod_co_filename,
            co_name=mod_co_name,
            co_firstlineno=mod_co_firstlineno,
        )
    else:
        modified_code = types.CodeType(
            mod_co_argcount,
            code.co_kwonlyargcount,
            mod_co_nlocals,
            code.co_stacksize,
            code.co_flags,
            code.co_code,
            code.co_consts,
            code.co_names,
            mod_co_varnames,
            mod_co_filename,
            mod_co_name,
            mod_co_firstlineno,
            code.co_lnotab
        )

    default_arg_values = tuple(p.default for p in parameters if p.default != Parameter.empty) #!argdefs "starts from the right"/"is right-aligned"
    modified_func = types.FunctionType(modified_code, {'dict_func': func, 'locals': locals}, name=func_name, argdefs=default_arg_values)
    modified_func.__doc__ = documentation
    modified_func.__signature__ = new_signature
    return modified_func

 

posted @ 2022-12-20 15:17  南方的墙  阅读(256)  评论(0编辑  收藏  举报