【问题标题】:Python 3 setter version of getargspec? Or other way to dynamically create named arguments?Python 3 setter 版本的 getargspec?或者其他动态创建命名参数的方法?
【发布时间】:2018-04-09 11:58:34
【问题描述】:

我碰巧有一些代码使用自省来了解函数的参数是什么,然后根据这些名称执行一些逻辑。例如,我可能会创建一些函数,例如

def func1(a,b):
    return a+b

def func2(a):
    return a

def func3(b):
    return b

并通过使用例如inspect.getargspec(func1) 我可以得到列表 ["a","b"] 返回。通过这种方式,我的代码可以检查某些函数是否具有相同的参数名称。

所以现在,我想动态地创建一堆函数,比如说另一个函数。示意图上我想做例如

def make_funcs():
    func_list = []
    for i in 10:
        def f(x_i): ***here x_i should be x_1, or x_2, etc.
            return x_i:
        func_list += [f]
    return func_list

其中,“x_i”实际上应该是 x_1、x_2 等。因此,当我使用 getargspec 检查这些函数时,结果是“x_1”、“x_2”等。以某种方式设置创建函数后的参数名称。因此,例如,我可以使用通用参数名称创建函数,然后稍后将其更改为所需的特定名称。

有什么方法可以做这些事情吗?

【问题讨论】:

  • getargspec 不创建参数。您的问题有点不清楚 - 发布您想要做什么的最小 sn-ps,并标记您要询问的伪代码行。
  • 是的,我知道它不会创建参数。它得到了他们。我正在尝试创建函数,以便 getargspec 返回我在问题中指出的结果。我已经标记了我想要更好地控制的伪代码行。

标签: python python-3.x functional-programming introspection


【解决方案1】:

使用**kwargs作为参数怎么样,所以参数名称不在函数定义中设置,但可以从dictkwargs检索?

顺便说一句,你应该提供一个例子,因为我没有清楚地理解不能依赖其参数名称来工作的函数的意义;)

【讨论】:

  • 进行自省的实际代码并不是特别简单或与问题相关,所以我不确定发布它是否有帮助。但它是优化例程的一部分,我正在最小化函数的乘积。如果这些函数的参数是独立的,那么我可以独立地最小化产品的每个组件,否则我必须进行更大维度的最小化。所以我需要知道哪些函数需要相同的参数,哪些是独立的。因此使用 **kwargs 是不好的,因为依赖结构被隐藏了。
  • 好的,所以基本上,想法是在运行时定义一个新函数,它的参数列表还没有固定,它的代码也没有,对吧?
  • 好吧,代码可以修复,没问题。事实上,这些函数都是相同的,但我需要以不同的方式命名参数。否则是的,就是这样。
  • 我不知道这是否可以实现。一种(丑陋的!)可能性是将函数编写为字符串,然后使用eval 创建该函数。
  • 哈哈,是的,我想过这个,但我想我会先检查一下是否有更好的方法......
【解决方案2】:

如果您只需要更改inspect.getargspec 读取函数签名的方式,您可以手工制作一个inspect.Signature 对象并将其分配给函数的__signature__ 属性:

import inspect

def f(x_i):
    return x_i

i = 0
param = inspect.Parameter('x_{}'.format(i), inspect.Parameter.POSITIONAL_ONLY)
f.__signature__ = inspect.Signature([param])

(另请参阅inspect.Parameter 构造函数的文档。)

这样设置签名可以与inspect.getfullargspecinspect.getargspec 的未弃用版本)和inspect.signature 正确交互:

>>> inspect.getfullargspec(f)
FullArgSpec(args=['x_0'], varargs=None, varkw=None, defaults=None,
            kwonlyargs=[], kwonlydefaults=None, annotations={})

但是,它实际上并没有改变参数的名称,所以关键字参数不能正常工作:

>>> f(x_0=3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f() got an unexpected keyword argument 'x_0'
>>> f(x_i=3)
3

如果您需要关键字参数才能正常工作,最简单的解决方案是使用 exec 动态创建函数:

i = 0

globs = {}
code = """
def f(x_{0}):
    return x_{0}
""".format(i)
exec(code, globs)
f = globs['f']
>>> f(3)
3
>>> f(x_0=3)
3

【讨论】:

  • 啊,这么近。我确实需要关键字参数才能正常工作,对这些参数名称进行自省的一半是知道要为它们使用哪些关键字参数。
  • 哈哈好吧,我想避免它,但是好吧,执行它。
猜你喜欢
  • 1970-01-01
  • 2011-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-29
相关资源
最近更新 更多