【问题标题】:In python is there any way I can obtain the arguments passed to a function as object?在 python 中,有什么方法可以获取作为对象传递给函数的参数?
【发布时间】:2009-12-27 19:00:36
【问题描述】:

我不想使用 *args 或 **kwargs,因为我无法更改函数声明。

例如:

def foo( a, b, c ) """Lets say values passed to a, b and c are 1,2 and 3 respectively"""
   ...
   ...
   """ I would like to generate an object preferably a dictionary such as {'a':1, 'b':2, 'c':3} """
   ...
   ...

谁能建议一种方法来做到这一点? 提前致谢。

【问题讨论】:

    标签: python function object arguments


    【解决方案1】:

    如果您不能更改函数“声明”(为什么不呢?)但您可以更改函数的内容,那么只需根据需要创建字典:

    def foo(a, b, c):
        mydict = {'a': a, 'b': b, 'c': c}
    

    如果这不起作用,我认为您需要更好地解释您想要什么以及您的情况有什么限制。

    这也将在上述情况下给出类似的结果(除了参数之外,您不显示任何局部变量),但请注意you should not try to modify locals()

    def foo(a, b, c):
        mydict = locals()
    

    【讨论】:

    • 无法复制locals() dict 解决问题,即mydict = locals().copy()?至少关于不修改mydict的问题?
    • @ndim,是的,只要避免修改 locals() 的问题,它就可以正常工作。根据他迄今为止给出的一点点,这是否会帮助我们不知道的 OP。
    • >>> >>> def foo(a, b, c): ... mydict = locals() ... mydict['a']=0 ... print mydict .. . print a ... >>> >>> foo(1,2,3) {'a': 0, 'c': 3, 'b': 2} 1 >>> 看起来我刚刚修改了mydict。 . 它没有抛出任何错误!
    • 请阅读我参考的文档。它没有说更改不会起作用,而是说“可能不会”。你想赌博吗?
    • @Peter hmm... 修改 mydict 不会在运行时修改局部变量... mydict 只是调用它时本地变量的快照,它只是另一个字典,因此可以对其进行修改。
    【解决方案2】:

    @Rohit,当您说“函数声明”时,我们不明白您的意思。如果您的意思是您不想更改函数的 API(函数调用的文档化方式),可能是因为现有代码已经在调用现有函数,那么您仍然可以使用 **kwargs 表示法,并且来电者永远不会知道:

    def foo(a, b, c):
        return a + b + c
    
    def foo(**kwargs):
        total = 0
        for x in ("a", "b", "c"):
            assert x in kwargs
            total += kwargs[x]
        return total
    
    def bar():
        foo(3, 5, 7)
    

    bar() 无法判断它正在调用哪个版本的foo(),并且不在乎。

    也许您正在寻找一个“包装器”,您可以包装现有的函数对象,而无需更改函数对象的实际源代码?

    def make_wrapper(fn, *arg_names):
        def wrapped_fn(*args):
            mydict = dict(tup for tup in zip(arg_names, args))
            print("TEST: mydict: %s" % str(mydict))
            return fn(*args)
        return wrapped_fn
    
    
    def foo(a, b, c):
        return a + b + c
    
    foo = make_wrapper(foo, "a", "b", "c")
    
    foo(3, 5, 7)
    

    新包装的函数将参数收集到mydict 并在调用函数之前打印mydict

    【讨论】:

    • @steveha 感谢您提供详细信息.. 是的,实际上我想要一个包装器功能,但我不想每次添加新功能时都添加对 make_wrapper 的调用.. 我会去一个装饰器,它将收集字典中的所有输入参数...使用“locals()”作为装饰器函数中的第一条语句。
    • 我不知道怎么写你想要的装饰器。如果你使用*args 来收集包装函数中的参数,你不会得到参数的名称(这就是为什么我要求你将参数名称传递给make_wrapper() 函数)。您真正想要的是从包装函数 inside 调用 locals() 的结果的快照;在调用函数之前或返回之后,您无法得到它。也许完美的解决方案需要破解 Python 字节码! Python Cookbook 中可能有一些内容。
    【解决方案3】:

    通过对StackOverflow的勤奋搜索,我found out如何做到这一点。您使用inspect 模块。

    import inspect
    
    def make_wrapper(fn):
        arg_names = inspect.getargspec(fn)[0]
        def wrapped_fn(*args, **kwargs):
            # mydict now gets all expected positional arguments:
            mydict = dict(tup for tup in zip(arg_names, args))
            # special name "__args" gets list of all positional arguments
            mydict["__args"] = args
            # mydict now updated with all keyword arguments
            mydict.update(kwargs)
            # mydict now has full information on all arguments of any sort
            print("TEST: mydict: %s" % str(mydict))
            return fn(*args, **kwargs)
        return wrapped_fn
    
    def foo(a, b, c, *args, **kwargs):
        # a, b, and c must be set; extra, unexpected args will go in args list
        return a + b + c
    
    foo = make_wrapper(foo)
    
    foo(3, 5, 7, 1, 2)
    # prints: TEST: mydict: {'a': 3, 'c': 7, 'b': 5, '__args': (3, 5, 7, 1, 2)}
    # returns: 15
    

    你去,一个完美的解决你所说的问题。它是一个包装器,您不需要传入参数,它应该适用于任何函数。如果您需要它来处理类对象或其他内容,您可以阅读inspect 的文档并了解如何操作。

    请注意,字典中当然不会保留顺序,因此您可能看不到我在测试时看到的确切顺序。但是字典中应该有相同的值。

    【讨论】:

      【解决方案4】:
      def foo(a, b, c):
        args = {"a": a, "b": b, "c": c}
      

      【讨论】:

      • 我想要这个用于任何一般功能。
      • 可能有比您要求的更好的方法来实现您真正想做的事情。 (所有参数的对象是一种手段,而不是目的。)在您询问您真正想要什么之前,我们无能为力。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-06-04
      • 2011-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多