On Tue, 16 Feb 2016 11:46 pm, srinivas devaki wrote: > Hi, > > a = b = c > > as an assignment doesn't return anything, i ruled out a = b = c as > chained assignment, like a = (b = c) > SO i thought, a = b = c is resolved as > a, b = [c, c]
That is one way of thinking of it. A better way would be: a = c b = c except that isn't necessarily correct for complex assignments involving attribute access or item assignment. A better way is: _temp = c a = _temp b = _temp del _temp except the name "_temp" isn't actually used. > at-least i fixed in my mind that every assignment like operation in > python is done with references and then the references are binded to > the named variables. > like globals()['a'] = result() That's broadly correct. > but today i learned that this is not the case with great pain(7 hours > of debugging.) > > class Mytest(object): > def __init__(self, a): > self.a = a > def __getitem__(self, k): > print('__getitem__', k) > return self.a[k] > def __setitem__(self, k, v): > print('__setitem__', k, v) > self.a[k] = v > > roots = Mytest([0, 1, 2, 3, 4, 5, 6, 7, 8]) > a = 4 > roots[4] = 6 > a = roots[a] = roots[roots[a]] `roots[4] = 6` will give "__setitem__ 4 6", as you expect. On the right hand side, you have: roots[roots[a]] which evaluates `roots[a]` first, giving "__getitem__ 4". That returns 6, as you expect. So now you have `roots[6]`, which gives "__getitem__ 6", as you expect, and returns 6. The left hand side has: a = roots[a] = ... which becomes: a = roots[a] = 6 which behaves like: a = 6 roots[a] = 6 So you end up with: a = roots[6] = 6 which gives "__setitem__ 6 6", **not** "__setitem__ 4 6" like you expected. Here is a simpler demonstration: py> L = [0, 1, 2, 3, 4, 5, 6] py> a = L[a//100] = 500 py> print a 500 py> print L [0, 1, 2, 3, 4, 500, 6] Let's look at the byte-code generated by the statement: a = L[a] = x The exact byte-code used will depend on the version of Python you have, but for 2.7 it looks like this: py> from dis import dis py> code = compile("a = L[a] = x", "", "exec") py> dis(code) 1 0 LOAD_NAME 0 (x) 3 DUP_TOP 4 STORE_NAME 1 (a) 7 LOAD_NAME 2 (L) 10 LOAD_NAME 1 (a) 13 STORE_SUBSCR 14 LOAD_CONST 0 (None) 17 RETURN_VALUE Translated to English: - evaluate the expression `x` and push the result onto the stack; - duplicate the top value on the stack; - pop the top value off the stack and assign to name `a`; - evaluate the name `L`, and push the result onto the stack; - evaluate the name `a`, and push the result onto the stack; - call setattr with the top three items from the stack. > SO isn't it counter intuitive from all other python operations. > like how we teach on how python performs a swap operation??? No. Let's look at the equivalent swap: py> L = [10, 20, 30, 40, 50] py> a = 3 py> a, L[a] = L[a], a Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: list assignment index out of range This is equivalent to: _temp1 = L[a] # 40 pushed onto the stack _temp2 = a # 3 pushed onto the stack a = _temp1 # 40 # rotate the stack, and pull the top item 40 L[a] = _temp2 # L[40] = 3 which obviously fails. Here's the byte-code: py> code = compile("a, L[a] = L[a], a", "", "exec") py> dis(code) 1 0 LOAD_NAME 0 (L) 3 LOAD_NAME 1 (a) 6 BINARY_SUBSCR 7 LOAD_NAME 1 (a) 10 ROT_TWO 11 STORE_NAME 1 (a) 14 LOAD_NAME 0 (L) 17 LOAD_NAME 1 (a) 20 STORE_SUBSCR 21 LOAD_CONST 0 (None) 24 RETURN_VALUE If you do the swap in the other order, it works: py> L = [10, 20, 30, 40, 50] py> a = 3 py> L[a], a = a, L[a] py> print a 40 py> print L [10, 20, 30, 3, 50] In all cases, the same rule applies: - evaluate the right hand side from left-most to right-most, pushing the values onto the stack; - perform assignments on the left hand side, from left-most to right-most. -- Steven -- https://mail.python.org/mailman/listinfo/python-list