[EMAIL PROTECTED] a écrit : > I'm working on a "TempFile" class that stores the data in memory until > it gets larger than a specified threshold (as per PEP 42). Whilst > trying to implement it, I've come across some strange behaviour. Can > anyone explain this? > > The test case at the bottom starts a TempFile at size 50 and prints its > type. It then increases the size to the threshold at which point > "self" is changed to being a TemporaryFile.
Changed how ?-) > It seems that the next > call correctly uses the write() method of TemporaryFile (since we don't > see "changing type" in the output). However, type(tmp) still equals > TempFile. Not only that, tmp can still access the method dummy() that > exists only in TempFile. > > #!/usr/bin/env python > from StringIO import StringIO > import tempfile > > class TempFile(StringIO, object): > """A temporary file implementation that uses memory unless > either capacity is breached or fileno is requested, at which > point a real temporary file will be created and the relevant > details returned > """ > def __init__(self, buffer, capacity): > """Creates a TempFile object containing the specified buffer. > If capacity is specified, we use a real temporary file once the > > file gets larger than that size. Otherwise, the data is stored > > in memory. > """ > self.capacity = capacity > if len(buffer) > capacity: > self = tempfile.TemporaryFile() assigning to 'self' in a method doesn't impact the object itself - it only rebinds the *local* name 'self' for the rest of the block. If you want to change the class of an object, you must assign to self.__class__ - but, while perfectly legal (and in fact the simplest possible implementation of the state pattern in Python), it may be somewhat risky. (snip) > def write(self, str): > self.seek(0, 2) # find end of file > if((self.tell() + len(str)) >= self.capacity): > print "changing type" > flo = tempfile.TemporaryFile() > flo.write(self.getvalue()) > self = flo > print type(self) Same comment here. (snip) Now for a practical solution : what you want is the strategy pattern. from StringIO import StringIO from tempfile import TemporaryFile import sys class TempFile(object): """A temporary file implementation that uses memory unless either capacity is breached or fileno is requested, at which point a real temporary file will be created and the relevant details returned """ _strategies = (StringIO, TemporaryFile) def __init__(self, buffer, capacity): """Creates a TempFile object containing the specified buffer. If capacity is specified, we use a real temporary file once the file gets larger than that size. Otherwise, the data is stored in memory. """ self.capacity = capacity self._delegate = self._strategies[len(buffer) > self.capacity]() self.write(buffer) def write(self, value): print >> sys.stderr, \ "about to write %d more characters" % len(value) if isinstance(self._delegate, self._strategies[0]): len_value = len(value) if len_value >= self.capacity: needs_new_strategy = True else: self.seek(0, 2) # find end of file needs_new_strategy = \ self.tell() + len_value >= self.capacity if needs_new_strategy: print >> sys.stderr, "changing strategy" new_delegate = self._strategies[1]() new_delegate.write(self.getvalue()) self._delegate = new_delegate self._delegate.write(value) def __getattr__(self, name): # Takes care of automatic delegation, # customize this according to your needs. # Hint : this will only be called if normal lookup # failed, so to control access to any _delegate's method, # just implement a method with same name try: return getattr(self._delegate, name) except AttributeError: # hide the delegation e = "object '%s' has no attribute '%s'" \ % (self.__class__.__name__, name) raise AttributeError(e) if __name__ == "__main__": print "testing tempfile:" tmp = TempFile("", 100) ten_chars = "1234567890" tmp.write(ten_chars * 5) print "tmp < 100: ", tmp._delegate.__class__.__name__ tmp.write(ten_chars * 5) print "tmp == 100: " , tmp._delegate.__class__.__name__ tmp.write("the last straw") print "tmp > 100: " , tmp._delegate.__class__.__name__ -- http://mail.python.org/mailman/listinfo/python-list