I have a question about the map
function in Python.
From what I understand, the function does not mutate the list it\'s operating on, but rather create
The data model of Python is based on a trilogy:
identifier - reference - object
.
string
written in the code. Other words are also used to designate the 'identifier' :
1) name
2) variable ; because this word is used by metonymy in mathematics to designate the symbols that represent the real mathematical variables, and the variables in a computer have conceptually the same functioning as the mathematical variables (their values can change).
This use in Python is a very bad habit in my opinion : it creates ambiguities and confusion with what is called 'variable' in computer science: "chunk of memory whose content can change".
The best is to use the word : identifier
.
An identifier and an object are binded in a certain namespace. Namespaces are displayed under the form of Python's dictionaries, but they ARE NOT dictionaries.
The binding of the identifier and the object is indirect, via the reference.
The binding of the identifier and the reference is direct, and realized in the SYMBOL TABLE (or symbol-table).
In computer science, a symbol table is a data structure used by a language translator such as a compiler or interpreter, where each identifier in a program's source code is associated with information relating to its declaration or appearance in the source, such as its type, scope level and sometimes its location.
http://en.wikipedia.org/wiki/Symbol_table
They say: identifiers. Precisely.
I rarely see allusions to symbol table, though it's the crucial thing that sheds light on the functioning of the Python's data model IMO.
In my opinion, the word
binding
doesn't designate a precise and unique mechanism but globally the set of all the mechanisms concerning the trilogy identifier - reference - object
.
I dont' pretend that I perfectly understood all the matters concerning the data and execution models of Python, and that the above considerations are the more exact and precisely expressed that can be done.
However, they allow me to have an operational understanding of what happens during executions of code.
I would be very happy to be corrected on some points if I am wrong (for exemple, I am very satisfied to have learnt from Michael Foord that the nature of namespaces is not being dictionary, which is only the way they are represented)
.
That said, I don't know what is called value and reference when the subject of passing something as argument in Python is discussed, and I have the impression that a lot of the persons that have expressed on the subject in numerous esoteric discussions don't know more than me. I think that there is no best and lucid opinion on the subject that this one of Alex Martelli:
"Trying to reuse terminology that is more generally applied to languages where "variables are boxes" to a language where "variables are post-it tags" is, IMHO, more likely to confuse than to help."
Alex Martelli
http://bytes.com/topic/python/answers/37219-value-reference
You misunderstand how references work in Python. Here, all names are references, there are no "values". Names are bound to objects. But =
doesn't modify the object that's pointed to by the name — it rebinds the name to a different object:
x = 42
y = x
# now:
# 'is' is a identity operator — it checks whether two names point to the
# exact same object
print x is y # => True
print x, y # 42 42
y = 69
# now y has been rebound, but that does not change the '42' object, nor rebinds x
print x is y # => False
print x, y # 42 69
To modify the object itself, it needs to be mutable — i.e. expose members that mutate it or have a modifiable dict. The same thing as above happens when you rebind p
— it doesn't touch points
at all, it simply modifies the meaning of local p
name.
If you want to simulate C++-like references, you need to encapsulate the object into a mutable container, e.g. a list.
reflect([points], 'X')
# inside reflect:
p[0] = ...
But you shouldn't, at least in this case — you should just return the new object instead.
points = reflect(points, 'X')
# inside reflect, instead of p = ...
return map(func, p)
Well, now that I think about it, you can also do
p[:] = map(func, p)
But again, returning new object is usually better.
I want to bump this. The answers don't really answer the question - they disregard the fact that the OP was able to achieve the desired result by iterating. The question comes down to the behavior of map
. Here is a more direct example:
f=(lambda pair: pair[0].append(pair[1]))
a = ([],1)
f(a)
print(a) #prints ([1],1)
a=([],1)
map(f,[a])
print(a) #prints ([0],1)
So map isn't mutating objects in the way the OP is expecting. I have the same confusion.
Can anyone comment on exactly what is going on here? I think that'd be a good answer to the OP's question.
Note that we have different behavior if we assign the output of map
as follows (as per Cat Plus Plus' answer)
f=(lambda pair: pair[0].append(pair[1]))
a = ([],1)
x = [a]
x[:] = map(f,x)
print(x) #prints None
print(a) # prints [1]
Please note that in the first example, we simply called f(a)
, not a=f(a)
. Why do we need assignment when using map
and not when working outside of map
?