Question

I'm trying to use the with..as contruct in Python to make writing "reversible computing" code easier. However, using @contextmanager on a class method seems to change the default initialization of future class instances. Python 2.6 and 3.1 have the same behavior. Here is a simple example exhibiting this behavior:

#!/usr/bin/env python

import contextlib

class SymList:
    def __init__(self, L=[]):
        self.L = L

    @contextlib.contextmanager
    def SymAdd(self, a):
        self.L.append(a)
        yield
        self.L.append(a)

SL = SymList()
with SL.SymAdd(3):
    SL.L.append(5)
print(SL.L) # Expect and see [3, 5, 3]
SL2 = SymList()
print(SL2.L) # Expect [] and see [3, 5, 3]


  • Why isn't SL2 a fresh instance of SymList?
  • How is the SL2.L data member referring to the SL.L data member?
Was it helpful?

Solution

This behavior is due to how mutable default arguments work in Python.

Try changing SymList.__init__() to the following:

    def __init__(self, L=None):
        if L is None:
             self.L = []
        else:
             self.L = L

As you modify self.L in one instance you are also modifying the L that is passed into SymList.__init__(), so the result with your code is that all instances would share the same L attribute when the instance is first initialized.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top