Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: Unexpected behavior using contextmanager on class method [duplicate]

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?
like image 741
user1582421 Avatar asked Dec 09 '22 22:12

user1582421


1 Answers

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.

like image 63
Andrew Clark Avatar answered Jan 21 '23 15:01

Andrew Clark