John Posner <jjpos...@snet.net> wrote: > Summary: I no longer suspect that "Python is broken". I *do* think that > there's a situation that is potentially quite confusing: > > * In the statement "self.x = self.x + 1", the two "self.x" names can > sometimes refer to different objects.
But this is fundamental to Python. The name (or slot, in the case of say a slice assignment) on the left hand side is being given a new binding by the assignment statement. So whatever object the 'self.x' on the left hand side may have pointed to before the statement is executed is irrelevant (if we ignore '+=' and kin). That is the essence of assignment in Python. If you are surprised by this, then you should probably study up a bit on the way namespaces work in Python. What I think you meant is that even though both are represented by the same token sequence in the source ('self.x'), the two 'x's are actually located in two different namespaces. The one on the left hand side of the assignment is local to the instance, while the one on the right hand side can cascade upward to the class namespace and resolve to an object from there. > * Even worse, in the equivalent statement "self.x += 1", the single name > "self.x" can sometimes refer to two different objects! Now on this one I'll agree with you about the "worse" part. Consider: >>> class A(object): ... x = [1] ... def f(self): ... self.x = self.x + [2] ... print self.x ... >>> >>> m = A() >>> m.f() [1, 2] >>> A.x [1] >>> class B(object): ... x = [1] ... def g(self): ... self.x += [2] ... print self.x ... >>> n = B() >>> n.g() [1, 2] >>> B.x [1, 2] I'm inclined to call that a problem, myself, even though I understand why it happens (+= mutates the object pointed to by the class variable 'x', and _then_ the instance variable 'x' is created and pointed at the same object. Whereas in the '+' case, a new list is created and the new 'x' instance variable is pointed at that new list.) There is a somewhat analogous situation with variables in the local scope of a function and global variables in the module. For example, we might have: >>> x = 1 >>> def f(): ... print x ... >>> f() 1 So, when 'x' isn't found locally, the value gets picked up from the global namespace. The difference from the class/instance case is when we try to assign to it: >>> def g(): ... x = x + 1 ... >>> g() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in g UnboundLocalError: local variable 'x' referenced before assignment >>> x = [] >>> def g(): ... x += [1] ... >>> g() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in g UnboundLocalError: local variable 'x' referenced before assignment So in this case Python is warning us about the namespace difference. Why are the two cases handled differently? To tell you the truth, I'm not sure. I've been programming in Python for years and it just seems to make sense to me to do it that way. It does allow you to use class variables as default values for instance variables, as long as you are careful when using mutable objects. But you could argue that it should behave in a way analogous to local/global. It would be interesting to see that argument laid out in full, with all the consequences it would entail examined. > I think this situation should be handled in documentation. (I'm a tech writer > in my day job ... oh wait, I forgot ... I got laid off from my day job in > December.) I'll look into what the standard Python doc set says on this > matter. Doc patches are always welcome, and from what I hear easier to get accepted than code patches ;) -- R. David Murray http://www.bitdance.com -- http://mail.python.org/mailman/listinfo/python-list