On Sat, 13 Nov 2010 20:01:42 +0000, Mark Wooding wrote: > Terry Reedy <tjre...@udel.edu> writes: > >> On 11/13/2010 11:29 AM, Mark Wooding wrote: >> >> > Alas, Python is actually slightly confusing here, since the same >> > notation `=' sometimes means assignment and sometimes means mutation. >> >> I disagree somewhat. An object is mutated by an internal assignment. > > Some object types are primitive, provided by the runtime system; there > are no `internal' variables to be assigned in these cases.
You seem to be making up your own terminology here, or at least using terminology that isn't normally used in the languages I'm used to. In OO languages such as Python, Java, and (I believe) Ruby, it is conventional to distinguish between objects and "primitives". Primitives are implemented as low-level C-like variables. In that sense, Python has no primitives. Ints, floats, etc. (which are primitives in Java) are full-blown objects in Python. If you mean "primitive" in the sense of "built-in", your conclusion is wrong. Such "primitive" types include dicts and lists, which are sophisticated container objects with internal "variables" to be assigned to: alist[0] = None assigns the value None to the first position in the list. Just because these "variables" aren't *named* variables doesn't mean they don't vary, or that they can't be assigned to. If you mean "primitive" in some other sense, I'm afraid I can't guess what you mean. >> "ll[0] = 1" assigns 1 to the 0 slot of ll. "o.a = 1" assigns 1 to the >> 'a' attribute of o. This which might be implemented by assigning 1 to >> the 'a' slot of o.__dict__, just as "a=1" might be implemented by >> assigning 1 to the 'a' slot of a namespace dict. > > There's a qualitative difference here: simple assignment has semantics > defined by the language and provided by the implementation, and can > therefore be understood in isolation, using only lexically apparent > information; whereas the complex assignments are implemented by invoking > methods on the objects mentioned on the left hand side. Again, you're using unfamiliar terminology. "Simple" and "complex" assignment -- I can guess you mean "name binding" = simple and "any other reference binding" = complex in Python terminology: name = value # simple assignment dict[key] = value # complex assignment obj.attr = value # complex The thing is, the semantics of assigning to built-in components are equally defined by the language as the semantics of name binding. If x is a built-in list or dict, the semantics of: x[something] = value is written in stone and part of the language semantics. Whether that is implemented by a method or not is an irrelevant implementation detail, but for what little it's worth, I believe the CPython implementation is written in a fully procedural fashion, with no methods in sight. One can write: [0, 1, 2, 3, 4][2] = 5 and the language semantics tell you *exactly* what will happen: the value of the list in position 2 will be unbound and the object 5 will be bound in its place. Who cares whether the *implementation* happens to be written as a C function or a Java method, or something else? You are right to point out that for arbitrary types: x[2] = 5 need not be an assignment, since if x is not a built-in x.__setitem__ will be called, and it may do anything it likes. By contrast, name binding: x = 5 *never* calls a method on any object, and therefore is fully defined by the language semantics. The distinction between the two count as an important proviso to the discussion: x[2] = 5 is only an assignment if the type of x is non-pathological and not broken. But putting aside such pathological cases, I don't think you can justify distinguishing between "simple" and "complex" assignment. Names are only one type of reference in Python, not the only one, and assignments other than name-binding can be fully understood from the language semantics *provided you know the type is a built-in*. >> Assignment *always* binds an object to a target. > > No! Assignment /never/ binds. A shocking claim that requires more explanation. If it doesn't bind, what does it do? > There is syntactic confusion here too, > since Python interprets a simple assignment in a function body -- in the > absence of a declaration such as `global' to the contrary -- as > indicating that the variable in question should be bound to a fresh > variable on entry to the function. Well, there seems to be some confusion here, but I don't think it's ours... local variables in functions aren't bound on *entry* to the function. How could they be? They are bound *when the assignment is executed*, which may be never -- hence it is possible to get an UnboundLocalError exception, if you try to retrieve the value of a local which hasn't yet had a value bound to it. > But assignment itself doesn't > perform binding. (This is a persistent error in the Python community; > or, less charitably, the Python community gratuitously uses the word in > a different sense from the wider programming-language-theory community. > See Lisp literature passim, for example.) *Less* charitably? I'm sorry, you think that being *wrong* is better than being *different*? That's not a moral judgment I can agree with. > There's a two step mapping: names -> storage locations -> values. > Binding affects the left hand part of the mapping; assignment affects > the right hand part. That gratuitously conflates the implementation ("storage locations") with the interface. Objects in Python have no storage location, they float in the aether, free to move if the implementation chooses to move them... the CPython implementation doesn't, but some other implementation might do so, but either way *you can't tell the difference* from Python. There is nothing you can write in pure Python that can tell whether the storage location of an object has changed, or even whether "storage location" is a well-defined concept. Nothing in the semantics of Python demand that objects must be implemented as single contiguous blocks of data with a well-defined location. If you can think of an alternative, you're free to write an implementation that uses it. The closest you can come is that CPython exposes the memory location as the id(), but that's not a language promise: Jython and IronPython do not. -- Steven -- http://mail.python.org/mailman/listinfo/python-list