Prev: Communicating with a program using subprocess
Next: Could not import external source folder in Pydev
From: bart.c on 17 Jun 2010 19:20 "J Kenneth King" <james(a)agentultra.com> wrote in message news:87wrtxh0dq.fsf(a)agentultra.com... > candide <candide(a)free.invalid> writes: > >> Let's the following code : >> >>>>> t=[[0]*2]*3 >>>>> t >> [[0, 0], [0, 0], [0, 0]] >>>>> t[0][0]=1 >>>>> t >> [[1, 0], [1, 0], [1, 0]] >> >> Rather surprising, isn't it ? > > Not at all, actually. The code is clearly trying to set only t[0][0] to 1, not t[1][0] and t[2][0] as well. This behaviour is quite scary actually, especially when t[0]=42 *does* work as expected, while t[0][0]=42 is apparently duplicated. It appears inconsistent. > I'd be surprised if the multiplication operator was aware of object > constructors. Even arrays are "objects" in Python. Should the > multiplication operator know how to instantiate three arrays from a > single array instance? What about an instance of a user-defined class? Multiplication operators shouldn't need to be directly aware of any such thing; it should just request that an object be duplicated without worrying about how it's done. I don't know how Python does things, but an object should either specify a special way of duplicating itself, or lend itself to some standard way of doing so. (So for a list, it's just a question of copying the data in the list, then recursively duplicating each new element..) -- Bartc
From: Benjamin Kaplan on 17 Jun 2010 19:44 On Thu, Jun 17, 2010 at 4:20 PM, bart.c <bartc(a)freeuk.com> wrote: > > "J Kenneth King" <james(a)agentultra.com> wrote in message > news:87wrtxh0dq.fsf(a)agentultra.com... >> >> candide <candide(a)free.invalid> writes: >> >>> Let's the following code : >>> >>>>>> t=[[0]*2]*3 >>>>>> t >>> >>> [[0, 0], [0, 0], [0, 0]] >>>>>> >>>>>> t[0][0]=1 >>>>>> t >>> >>> [[1, 0], [1, 0], [1, 0]] >>> >>> Rather surprising, isn't it ? >> >> Not at all, actually. > > The code is clearly trying to set only t[0][0] to 1, not t[1][0] and t[2][0] > as well. > > This behaviour is quite scary actually, especially when t[0]=42 *does* work > as expected, while t[0][0]=42 is apparently duplicated. It appears > inconsistent. > >> I'd be surprised if the multiplication operator was aware of object >> constructors. Even arrays are "objects" in Python. Should the >> multiplication operator know how to instantiate three arrays from a >> single array instance? What about an instance of a user-defined class? > > Multiplication operators shouldn't need to be directly aware of any such > thing; it should just request that an object be duplicated without worrying > about how it's done. > > I don't know how Python does things, but an object should either specify a > special way of duplicating itself, or lend itself to some standard way of > doing so. (So for a list, it's just a question of copying the data in the > list, then recursively duplicating each new element..) > > -- > Bartc It's the recursively duplicating each element that's the problem. How do you know when to stop?
From: rantingrick on 17 Jun 2010 20:48 On Jun 17, 6:44 pm, Benjamin Kaplan <benjamin.kap...(a)case.edu> wrote: > It's the recursively duplicating each element that's the problem. How > do you know when to stop? Thats easy, stack overflow! ;-)
From: Lie Ryan on 17 Jun 2010 21:38 On 06/18/10 09:20, bart.c wrote: > > "J Kenneth King" <james(a)agentultra.com> wrote in message > news:87wrtxh0dq.fsf(a)agentultra.com... >> candide <candide(a)free.invalid> writes: >> >>> Let's the following code : >>> >>>>>> t=[[0]*2]*3 >>>>>> t >>> [[0, 0], [0, 0], [0, 0]] >>>>>> t[0][0]=1 >>>>>> t >>> [[1, 0], [1, 0], [1, 0]] >>> >>> Rather surprising, isn't it ? >> >> Not at all, actually. > > The code is clearly trying to set only t[0][0] to 1, not t[1][0] and > t[2][0] > as well. > > This behaviour is quite scary actually, especially when t[0]=42 *does* work > as expected, while t[0][0]=42 is apparently duplicated. It appears > inconsistent. I agree, the behavior is often quite inconvenient, but I disagree that it is inconsistent. List multiplication behavior is consistent with the tenet: "objects are never copied unless explicitly requested" Peeking further: t = [[0] * 2] * 3 print id(t[0]) == id(t[1]) # True print id(t[0][0]) == id(t[1][0]) # True so, it is consistent (though it is quite inconvenient). >> I'd be surprised if the multiplication operator was aware of object >> constructors. Even arrays are "objects" in Python. Should the >> multiplication operator know how to instantiate three arrays from a >> single array instance? What about an instance of a user-defined class? > > Multiplication operators shouldn't need to be directly aware of any such > thing; it should just request that an object be duplicated without > worrying about how it's done. > > I don't know how Python does things, but an object should either specify > a special way of duplicating itself, or lend itself to some standard way > of doing so. (So for a list, it's just a question of copying the data in > the list, then recursively duplicating each new element..) That is inconsistent with the tenet. Moreover, the implicit copying makes it quite difficult to reason about the program's behavior. How would you propose this list should be copied: class O(object): def __init__(self): self.attr = 0 def add(self): self.attr += 1 b = [[O()] * 2] * 3
From: Steven D'Aprano on 18 Jun 2010 01:36 On Fri, 18 Jun 2010 00:20:30 +0100, bart.c wrote: > The code is clearly trying to set only t[0][0] to 1, not t[1][0] and > t[2][0] as well. Trying to guess the motivation of the person writing code is tricky, but in this case, that's a reasonable assumption. I can't think of any reason why somebody would explicitly *want* that behaviour: # Does it make sense to talk of anonymous aliases? list_of_aliases = [[0]*2]*3 list_of_aliases[0][0] = 1 assert list_of_aliases[0][1] == 1 so it is a safe guess that anyone writing [[0]*2]*3 has probably made a mistake. However, I've certainly done something like this: a = [0]*2 my_instance.items = a a[0] = 1 assert my_instance.items[0] = 1 This is the same fundamental behaviour with the same cause: Python does not copy objects unless you explicitly tell it to. I cheerfully accept that the behaviour of [[0]*2]*3 is a Gotcha, but it follows logically from Python's object model and assignment rules. If you are surprised by it, it just goes to show that your understanding of Python has at least one hole in it. > This behaviour is quite scary actually, especially when t[0]=42 *does* > work as expected, while t[0][0]=42 is apparently duplicated. It appears > inconsistent. Emphasis on the word "appears". It actually displays a deep consistency with the language fundamentals. If you're ever interviewing somebody for a position as Python developer, this is a quick test to distinguish those who know the language from those who know the language *well*. >> I'd be surprised if the multiplication operator was aware of object >> constructors. Even arrays are "objects" in Python. Should the >> multiplication operator know how to instantiate three arrays from a >> single array instance? What about an instance of a user-defined class? > > Multiplication operators shouldn't need to be directly aware of any such > thing; it should just request that an object be duplicated without > worrying about how it's done. The multiplication operator is not a duplicator (copier). It is a *repetition* operator: repeat the object N times, not make N copies. > I don't know how Python does things, Well there you go :) > but an object should either specify > a special way of duplicating itself, or lend itself to some standard way > of doing so. import copy copy.copy(obj) Dicts have a copy() method as a shortcut, and for lists you can use slicing: L = [1,2,3] Lcopy = L[:] > (So for a list, it's just a question of copying the data in > the list, then recursively duplicating each new element..) There's nothing "just" about that. Consider: L = [1, 2] L.append(L) How would you copy that? The correct answer is: x = copy.deepcopy(L) -- Steven
First
|
Prev
|
Next
|
Last
Pages: 1 2 3 Prev: Communicating with a program using subprocess Next: Could not import external source folder in Pydev |