[Tutor] The trap of the year
Steven D'Aprano
steve at pearwood.info
Wed Jan 26 00:33:34 CET 2011
Karim wrote:
>
> Hello All,
>
> Just to share on rageous bug I encounter where 2 lists which "should" to
> be different (same id) because hold by different instances of the same
> class are not in fact DIFFERENT, see below:
I think you are confused. If the two lists have the same ID, they should
be the same, not different.
> >>> class Device():
> ... def __init__(self, parameters=[]):
> ... self.parameters = parameters
This creates a list ONCE, when the method is created, and then uses that
same list over and over again.
Consider this:
>>> import time
>>> now = time.ctime()
>>> now
'Wed Jan 26 10:05:31 2011'
>>> def test(t=now):
... print(t)
...
>>> test()
Wed Jan 26 10:05:31 2011
>>> time.sleep(60); test()
Wed Jan 26 10:05:31 2011
Are you surprised that time.ctime() only gets called *once*? I hope not
-- I would expect that you consider this example obvious and not surprising.
How about this instead?
>>> def test2(t=time.ctime()):
... print(t)
...
>>> test2()
Wed Jan 26 10:09:10 2011
>>> time.sleep(60); test2()
Wed Jan 26 10:09:10 2011
I hope that this also will not be surprising. time.ctime() is called
once, when the function is created, and the result used as often as needed.
It is no different when the default value is a list like []. The list is
created once, and used each time the function is called.
> When I discovered that I was puzzled because at the prompt:
>
> >>> a = []
> >>> b = []
> >>> id(a)
> 140559202956496
> >>> id(b)
> 140559202957000
But this test is completely different. You create TWO lists, not one. A
better test would be:
>>> a = []
>>> b = a
>>> id(a), id(b)
(3083146668, 3083146668)
> I am not really understanding why my init in the class made it refers to
> the same list object.
Because it only creates one list, when the method is defined, not each
time the method is called.
Only the *inside* of the method is executed each time the method is
called, not the method definition. If you want something to be executed
each time the method is called, you have to put it in the body of the
method:
>>> def test3(t=None):
... if t is None: t = time.ctime()
... print(t)
...
>>> test3()
Wed Jan 26 10:18:33 2011
>>> time.sleep(60); test3()
Wed Jan 26 10:19:37 2011
--
Steven
More information about the Tutor
mailing list