Python 可选参数
大家好,我最近刚开始学习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
对象里的那个也会被改变。
有没有办法每次都重新创建这个可选参数,使用这种可选参数的语法呢?
3 个回答
6
没错,默认参数只在函数定义的时候被计算一次。
一个可能的解决办法是把参数设置成一个类,而不是一个实例,像这样:
def foo(blah, klass = B):
b = klass()
# etc
15
你需要做以下几点:
class A:
def __init__(self, builds=None):
if builds is None:
builds = B()
self.builds = builds
这是一个很常见的错误,就是把可变的参数当作默认参数来使用。可能在StackOverflow上有很多类似的问题。
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