Python可选参数

时间:2009-10-18 16:05:45

标签: python optional-arguments

伙计们,我刚刚开始使用python并且对可选参数感到困惑,比如我有这样的程序:

class B:
   pass

class A:
    def __init__(self, builds = B()):
        self.builds = builds

如果我创建两次

b = A()
c = A()

并打印他们的版本

print b.builds
print c.builds

我发现他们正在使用完全相同的对象,

<__main__.B instance at 0x68ee0>
<__main__.B instance at 0x68ee0>

但这不是我想要的,因为如果b改变了某些内部构建状态,c对象中的那个也将被更改。

是否可以通过使用此可选参数语法每次重新创建此可选参数?

3 个答案:

答案 0 :(得分:47)

您需要了解默认值的工作原理才能有效地使用它们。

功能是对象。因此,他们有属性。所以,如果我创建这个函数:

>>> def f(x, y=[]):
        y.append(x)
        return y

我创建了一个对象。以下是它的属性:

>>> dir(f)
['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__',   
'__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__',    
'__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', 
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 
'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 
'func_name']

其中一个是func_defaults。听起来很有希望,那里有什么?

>>> f.func_defaults
([],)

这是一个包含函数默认值的元组。如果默认值是对象,则元组包含该对象的实例。

如果您认为f将一个项目添加到列表中,如果没有提供列表则返回仅包含该项目的列表,这会导致一些相当违反直觉的行为:

>>> f(1)
[1]
>>> f(2)
[1, 2]

但是如果你知道默认值是一个存储在一个函数属性中的对象实例,那么它就不那么违反直觉:

>>> x = f(3)
>>> y = f(4)
>>> x == y
True
>>> x
[1, 2, 3, 4]
>>> x.append(5)
>>> f(6)
[1, 2, 3, 4, 5, 6]

了解这一点,很明显,如果您希望函数参数的默认值为新列表(或任何新对象),则不能简单地在func_defaults中隐藏对象的实例。每次调用函数时都必须创建一个新的:

>>>def g(x, y=None):
       if y==None:
           y = []
       y.append(x)
       return y

答案 1 :(得分:15)

您需要执行以下操作:

class A:
    def __init__(self, builds=None):
        if builds is None:
            builds = B()
        self.builds = builds

这是一个非常广泛的错误,使用可变参数作为默认参数。 SO上可能有很多傻瓜。

答案 2 :(得分:6)

是;默认参数仅在定义函数时进行评估。

一种可能的解决方案是让参数为而不是实例,la

def foo(blah, klass = B):
    b = klass()
    # etc