Python 可选参数

Posted

技术标签:

【中文标题】Python 可选参数【英文标题】:Python optional parameters 【发布时间】:2010-12-07 19:12:48 【问题描述】:

各位,我最近刚开始使用python,对可选参数感到困惑,说我有这样的程序:

class B:
   pass

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

如果我创建 A 两次

b = A()
c = A()

并打印他们的构建

print b.builds
print c.builds

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

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

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

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

【问题讨论】:

如果它解决了您的问题,您应该接受一个答案!有几个答案似乎非常有用。尽管问题很老,但我认为最好在回复中给予您的认可 "Least Astonishment" in Python: The Mutable Default Argument 的可能重复项 【参考方案1】:

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

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

>>> 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

【讨论】:

【参考方案2】:

您需要执行以下操作:

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

这是一个非常普遍的错误,使用可变参数作为默认参数。 SO上可能有很多骗子。

【讨论】:

那么让我们找一个 dup 并关闭这个? 问题是这样的:你不能使用可变对象作为默认值。之前的副本都尝试过使用列表。这是第一次使用对象。这是尝试使用可变对象作为默认值的“标准问题”。【参考方案3】:

是的;默认参数仅在定义函数时计算。

一种可能的解决方案是将参数设置为 class 而不是实例,例如 la

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

【讨论】:

简而言之,不能使用可变对象作为默认值。 当然可以。类在 Python 中是可变的。它与可变/不可变无关。 使用可变对象会导致这个问题的确切混淆。当你使用一个类作为默认值时,你几乎总是实例化来创建一个对象。类的可变性无关紧要,因为您没有像使用列表或字典那样直接使用类。 OP中的混乱与“可变性”完全无关;它与错误的假设或期望有关,即在调用函数时而不是在定义函数时计算 default 子句中的表达式。我想你不知道“可变”是什么意思!

以上是关于Python 可选参数的主要内容,如果未能解决你的问题,请参考以下文章

Python 可选参数

Python 通用可选参数

Python 用可变数量的位置参数和可选参数装饰方法

多个可选参数python

Python argparse 可选 arg 需要其他参数

Python Falcon 框架:可选 URI 参数