#! /usr/bin/python
class my_class:
# 1. __init__
def __init__(self):
self.my_set = set()
# 2. __init__
#def __init__(self, arg_set = set()):
# self.my_set = arg_set
c1 = my_class()
c1.my_set.add('a')
print c1.my_set
c2 = my_class()
c2.my_set.add('b')
print c1.my_set
my_class有两种定义__init__
的方式:
如果我使用第一种方式,输出是预期的:
set(['a'])
set(['a'])
如果我使用第二种方式,输出是意外的:
set(['a'])
set(['a', 'b'])
第二种方式出了什么问题?如何修改C2(一个单独的对象),导致修改c1?
Edit: Updated the question title to reflect specific area of concern
答案 0 :(得分:5)
来自http://docs.python.org/2/reference/compound_stmts.html#function-definitions
当函数定义为时,将计算默认参数值 执行。这意味着表达式被评估一次,当时 定义函数,并使用相同的“预先计算”值 每次通话。这对了解何时来说尤为重要 default参数是一个可变对象,例如列表或字典: 如果函数修改了对象(例如通过将项附加到a list),默认值实际上已被修改。
这就是你的第二个方法每次都附加值的原因。
此外,像这样修改第二个__init__
def __init__(self, arg_set = set()):
print id(arg_set)
self.my_set = arg_set
现在,当您运行代码时,您将始终获得相同的地址(CPython中的id
函数返回内存中对象的地址)。 因此,每次调用函数时都不会创建默认参数,但是第一次评估时会创建默认参数。
答案 1 :(得分:1)
thefourtheye对这种行为的原因是完全正确的。如果你想使用构造函数的第二个版本,它应该是这样的:
def __init__(self, arg_set=None):
if arg_set is None:
self.my_set = set()
else:
self.my_set = arg_set