Python closure + global strangeness
python
Solution
I don't know why so many comments above contain the correct answer and no one dared to write an actual answer, so I'll do it hereby.
class ThisWorksNow(object):
def outer(self):
acc = []
def inner(msg):
acc.append(msg)
inner("Why doesn't")
inner(" this work?")
print "".join(acc)
ThisWorksNow().outer()
What is the difference?
Assigning a name to an object which is in the closure doesn't work in Python 2.x, because the Py3 keyword `nonlocal` is missing, so we have to find a workaround.
If we have to keep the name-to-object-binding constant, we have to change something else. In this case, it is the object, to which we add the content to be added.
The `print` line is not very elegant; maybe an object which prints its contents concatenated might be more suitable.
class StringBuilder(list): # class name stolen from Java
def __str__(self):
"""this makes the object printable in a way which represents the concatenated string"""
return "".join(self)
@property
def string(self):
"""this gives us a property which represents the concatenated string"""
return "".join(self)
# use whatever suits you better, one or both
With this, we can do that:
class ThisWorksNow(object):
def outer(self):
acc = StringBuilder()
def inner(msg):
acc.append(msg)
inner("Why doesn't")
inner(" this work?")
print acc
print acc.string # depending on what you take above
ThisWorksNow().outer()
Edit (append): Why does `global` not work?
We could achieve this with `global` as well, with 2 downsides.
`acc` would have to be made global on both places we use it
class WhyDoesntThisWork(object):
def outer(self):
global acc
acc = ''
def inner(msg):
global acc
acc = acc + msg
Hereby we "lift" both `acc` occurrences to "`global`" level.
`acc` could be modified from outside.
If we do `global acc` somewhere else, or we use `acc` on module level, our process can be tampered with. This should be avoided.
Problem
I expected this little snippet to print "Why doesn't this work?" Can someone help me understand why this doesn't work as I expect? I'm using Python 2.6, if this matters. ``` class WhyDoesntThisWork(object): def outer(self): acc = '' def inner(msg): global acc acc = acc + msg inner("Why doesn't") inner(" this work?") print acc WhyDoesntThisWork().outer() ``` - If I include the `global` statement I get a `NameError: global name 'acc' is not defined `. - If I don't include the `global` statement I get a `UnboundLocalError: local variable 'acc' referenced before assignment`.