60

可能重复:
参数的默认值作为实例方法的结果

虽然可以在 python 中为函数参数设置默认值:

def my_function(param_one='default')
    ...

似乎无法访问当前实例(self):

class MyClass(..):

    def my_function(self, param_one=self.one_of_the_vars):
        ...

我的问题:

  • 我无法访问当前实例来设置函数中的默认参数,这是真的吗?
  • 如果不可能:原因是什么?是否可以想象这在未来的 python 版本中是可能的?
4

4 回答 4

61

It's written as:

def my_function(self, param_one=None): # Or custom sentinel if None is vaild
    if param_one is None:
        param_one = self.one_of_the_vars

And I think it's safe to say that will never happen in Python due to the nature that self doesn't really exist until the function starts... (you can't reference it, in its own definition - like everything else)

For example: you can't do d = {'x': 3, 'y': d['x'] * 5}

于 2012-11-02T13:18:48.700 回答
24

它比你想象的要多得多。考虑默认值是静态的(=指向一个对象的常量引用)并存储在定义中的某处;在方法定义时进行评估;作为的一部分,而不是实例。由于它们是恒定的,因此它们不能依赖于self

这是一个例子。这是违反直觉的,但实际上非常有意义:

def add(item, s=[]):
    s.append(item)
    print len(s)

add(1)     # 1
add(1)     # 2
add(1, []) # 1
add(1, []) # 1
add(1)     # 3

这将打印1 2 1 1 3.

因为它的工作方式与

default_s=[]
def add(item, s=default_s):
    s.append(item)

显然,如果你修改default_s,它会保留这些修改。

有多种解决方法,包括

def add(item, s=None):
    if not s: s = []
    s.append(item)

或者你可以这样做:

def add(self, item, s=None):
    if not s: s = self.makeDefaultS()
    s.append(item)

然后该方法makeDefaultS将有权访问self.

另一种变化:

import types
def add(item, s=lambda self:[]):
    if isinstance(s, types.FunctionType): s = s("example")
    s.append(item)

这里的默认值s工厂函数

您可以结合所有这些技术:

class Foo:
    import types
    def add(self, item, s=Foo.defaultFactory):
        if isinstance(s, types.FunctionType): s = s(self)
        s.append(item)

    def defaultFactory(self):
        """ Can be overridden in a subclass, too!"""
        return []
于 2012-11-02T13:22:55.583 回答
3

参数的默认值在“编译”时评估一次。所以显然你不能访问self. 经典示例list作为默认参数。如果向其中添加元素,则参数的默认值会更改!

解决方法是使用另一个默认参数,通常是None,然后检查并更新变量。

于 2012-11-02T13:20:47.710 回答
2

您在这里做出了多个错误的假设 - 首先,函数属于一个类而不是一个实例,这意味着所涉及的实际函数对于一个类的任何两个实例都是相同的。其次,默认参数在编译时评估并且是常量(如常量对象引用 - 如果参数是可变对象,您可以更改它)。因此,您无法访问self默认参数,也永远无法访问。

于 2012-11-02T13:24:07.937 回答