【问题标题】:Where is the default parameter in Python functionPython函数中的默认参数在哪里
【发布时间】:2012-04-24 15:29:35
【问题描述】:

我想很多人都见过接受默认参数的python函数。例如:

def foo(a=[]):
    a.append(3)
    return a

如果我们使用 foo() 调用此函数,则每次调用后输出都会附加整数 '3'。

定义此函数时,会在当前环境中定义一个名为 'foo' 的函数对象,同时也会评估默认参数值。每次调用不带参数的函数时,计算出来的参数值都会根据代码发生变化。

我的问题是,这个评估参数在哪里存在? 调用函数时是在函数对象中还是在方法对象中? 由于python中的一切都是一个对象,因此必须有一些地方来保存'a'-->已评估参数的名称->值绑定。我是不是在想这个问题?

【问题讨论】:

    标签: python


    【解决方案1】:

    正如其他人已经说过的,默认值存储在函数对象中。

    例如,在 CPython 中你可以这样做:

    >>> def f(a=[]):
    ...     pass
    ...
    >>> f.func_defaults
    ([],)
    >>> f.func_code.co_varnames
    ('a',)
    >>>
    

    但是,co_varnames 可能包含多个参数名称,因此需要进一步处理,并且这些属性甚至可能在其他 Python 实现中不存在。因此,您应该改用 inspect 模块,它会为您处理所有实现细节:

    >>> import inspect
    >>> spec = inspect.getargspec(f)
    >>> spec
    ArgSpec(args=['a'], varargs=None, keywords=None, defaults=([],))
    >>>
    

    ArgSpec 是一个命名元组,因此您可以将所有值作为属性访问:

    >>> spec.args
    ['a']
    >>> spec.defaults
    ([],)
    >>>
    

    正如documentation 所说,defaults 元组始终对应于来自args 的最后 n 个参数。这将为您提供映射。

    要创建一个字典,你可以这样做:

    >>> dict(zip(spec.args[-len(spec.defaults):], spec.defaults))
    {'a': []}
    >>>
    

    【讨论】:

      【解决方案2】:

      附加在函数对象上,见foo.func_defaults

      >>> foo()
      >>> foo.func_defaults
      ([3],)
      >>> foo()
      >>> foo.func_defaults
      ([3, 3],)
      

      如果你想得到a[]的映射,你可以访问foo.func_code

      defaults = foo.func_defaults
      # the args are locals in the beginning:
      args = foo.func_code.co_varnames[:foo.func_code.co_argcount] 
      def_args = args[-len(defaults):]  # the args with defaults are in the end
      print dict(zip(def_args, defaults)) # {'a': []}
      

      (但是,显然牦牛的版本更好。)

      【讨论】:

      • 是的,但是按照 OP 的要求,a[] 的映射在哪里?
      【解决方案3】:

      在函数对象中,在func_defaults:

      def f(a=[]): a.append(3)
      
      print f.func_defaults # ([],)
      
      f()
      
      print f.func_defaults # ([3],)
      

      【讨论】:

      • 是的,但是按照 OP 的要求, a 到 [] 的映射在哪里?
      【解决方案4】:

      存储在函数对象的func_defaults属性中。

      >>> foo.func_defaults
      ([],)
      >>> foo()
      ([3],)
      

      【讨论】:

        【解决方案5】:

        我发现了一个有趣的情况:在python 2.5.2版本中,尝试函数'foo()'

        >>> foo()
        [1]
        >>> foo()
        [1]
        >>> foo()
        [1]
        

        因为被调用的函数的对象不同:

        >>> id(foo())
        4336826757314657360
        >>> id(foo())
        4336826757314657008
        >>> id(foo())
        4336826757314683160
        

        在 2.7.2 版本中:

        >>> foo()
        [1]
        >>> foo()
        [1, 1]
        >>> foo()
        [1, 1, 1]
        

        在这种情况下,每次调用函数的对象都是相同的:

        >>> id(foo())
        29250192
        >>> id(foo())
        29250192
        >>> id(foo())
        29250192
        

        是不是版本不同的问题?

        【讨论】:

        • 不应该发生。确保您在两个版本上完全使用相同的功能。
        猜你喜欢
        • 2019-09-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-26
        • 1970-01-01
        相关资源
        最近更新 更多