Python的types.FunctionType如何创建动态函数?

前端之家收集整理的这篇文章主要介绍了Python的types.FunctionType如何创建动态函数?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

我正在努力增强我的Python技能,我遇到了使用types.FunctionType的Open-Source code for Saltstack,我不明白发生了什么.

salt.cloud.clouds.cloudstack.py

函数create()包含以下代码

kwargs = {
    'name': vm_['name'],'image': get_image(conn,vm_),'size': get_size(conn,'location': get_location(conn,}

函数get_image和get_size传递给函数’namespaced_function’,如下所示:

get_size = namespaced_function(get_size,globals())
get_image = namespaced_function(get_image,globals())

salt.utils.functools.py

具有命名空间功能

def namespaced_function(function,global_dict,defaults=None,preserve_context=False):
    '''
    Redefine (clone) a function under a different globals() namespace scope
        preserve_context:
            Allow keeping the context taken from orignal namespace,and extend it with globals() taken from
            new targetted namespace.
    '''
    if defaults is None:
        defaults = function.__defaults__

    if preserve_context:
        _global_dict = function.__globals__.copy()
        _global_dict.update(global_dict)
        global_dict = _global_dict
    new_namespaced_function = types.FunctionType(
        function.__code__,name=function.__name__,argdefs=defaults,closure=function.__closure__
    )
    new_namespaced_function.__dict__.update(function.__dict__)
    return new_namespaced_function

我可以看到他们正在动态创建一个函数get_image,但我不明白这样做的好处.为什么不创建这个功能呢?

最佳答案
由于namespaced_function()将(旧)函数get_image()作为参数并返回(new)get_image()函数,因此更容易说它正在修改函数,而不是创建函数.当然,它正在创建一个函数并返回它,但它非常类似于输入函数. namespaced_function()有点像装饰器,但装饰器通常只是将整个输入函数包装在另一个调用原始函数函数中,而不是实际创建原始函数修改版本.原始get_image()定义为libcloudfuncs.py.

所以问题就变成了,“namespaced_function()如何修改输入函数?”.如果您查看了什么类型.FunctionType()作为其参数,您会看到大多数值直接从原始函数复制.唯一没有直接复制的参数是函数全局变量.换句话说,namespaced_function()正在创建一个新函数,它在输入函数的每个方面都是相同的,除了当函数引用全局变量时,它在不同的地方查找它们.

因此,他们正在创建一个新版本的get_image(),它也可以访问当前模块的全局变量.他们为什么这样做?好吧,要么覆盖一些全局变量,要么提供原始模块中根本不存在的变量(在这种情况下,原始函数修改之前会被故意破坏).但我真的不能回答“为什么?”除了简单地说他们可能认为它比替代品更容易.

那有什么选择呢?嗯,全局变量往往不受欢迎 – 当它们不是常数时 – 因为,你可能想要改变它们.他们本可以使用额外的参数而不是全局变量,但是当他们的大多数函数使用它们时,他们可能不希望继续传递相同的参数.你也可以注入参数,就像它们注入全局变量一样 – 而且它也不那么hacky!那他们为什么不这样做呢?好吧,再次,我有点猜测,但他们可能有不止一个全局变量,他们正在改变/提供.

自动提供参数很容易:

def original(auto1,arg1,arg2,auto2):
    print(auto1,auto2,arg2)

injected = functools.partial(original,'auto1',auto2='auto2')

injected(1,2) # is equal to original('auto1',1,2,'auto2')

自动提供大量参数会很快变得乏味.

当然,您可能只是让所有函数都有一个名为eg的参数. globals作为第一个参数,并使用inject = functools.partial(original,globals()).但是在函数内部,每当你需要引用这样一个变量时,你需要说全局变量[‘变量’]而不仅仅是变量.

所以,总的来说,它可能有点hacky,但作者可能认为“有点hacky”仍然比更冗长的替代方案好很多.

猜你在找的Python相关文章