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()
global
statement I get a NameError: global name 'acc' is not defined
.global
statement I get a UnboundLocalError: local variable 'acc' referenced before assignment
.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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With