persistent deque

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • castironpi

    persistent deque

    I'd like a persistent deque, such that the instance operations all
    commit atomicly to file system.
  • inhahe

    #2
    Re: persistent deque

    "castironpi " <castironpi@gma il.comwrote in message
    news:29451c2a-cb0a-43a6-b140-6c16e3cb46ac@c6 5g2000hsa.googl egroups.com...
    I'd like a persistent deque, such that the instance operations all
    commit atomicly to file system.
    ok, i made your persistent deque. but there are two important notes
    regarding this module: 1) I am a genius. 2) it doesn't actually work for
    some reason. i.e., loading an instance from file won't work. i don't know
    why. the pickle module is doing something i didn't expect.


    from collections import deque
    import os, pickle, random

    class pdeque(deque):
    def __init__(self, filename, initial):
    deque.__init__( self, initial)
    self.filename = filename
    self.tempfilena me = ''.join((random .choice("abcdef ghijklmnopqrstu vwxyz")
    for x in xrange(10)))+". tmp"
    self.save()
    def save(self):
    pickle.dump(sel f, open(self.tempf ilename,'wb'))
    try: os.remove(self. filename)
    except: pass
    os.rename(self. tempfilename, self.filename)
    @classmethod
    def load(cls, filename):
    return pickle.load(ope n(filename,'rb' ))

    for name in "append appendleft extend extendleft remove rotate".split() :
    func = getattr(deque, name)
    def func2(instance, arg, func=func):
    result = func(instance, arg)
    instance.save()
    return result
    setattr(pdeque, name, func2)

    for name in ("pop", "popleft", "clear"):
    func = getattr(deque, name)
    def func2(instance, func=func):
    result = func(instance)
    instance.save()
    return result
    setattr(pdeque, name, func2)


    ---

    you use it just like a deque object except that when initializing the first
    parameter is a filename for it to store in. to load the deque object again
    later, call .load(filename) on the pdeque class or a pdeque object (except
    that it doesn't work.)

    i'm sure somebody here knows what obscure feature of pickling it is that's
    doing this counterintuitiv ely. (disclaimer: i've never used pickle to store
    a custom type before)



    Comment

    • inhahe

      #3
      Re: persistent deque

      def __init__(self, filename, initial):

      should be

      def __init__(self, filename, initial=[]):

      (that was the whole reason i put the filename first.)

      sorry.



      Comment

      • Larry Bates

        #4
        Re: persistent deque

        inhahe wrote:
        def __init__(self, filename, initial):
        >
        should be
        >
        def __init__(self, filename, initial=[]):
        >
        (that was the whole reason i put the filename first.)
        >
        sorry.
        >
        >
        >
        Defaulting initial to empty list this way is asking for trouble. You should
        default it to None and check for None and reset to empty list.

        -Larry

        Comment

        • inhahe

          #5
          Re: persistent deque

          oh yeah! thanks for pointing it out, i should have thought of that, i
          *just* read about it today, or was it yesterday.

          so what's the problem with pickle? i have a feeling, maybe i read it, that
          when you pickle a derived class it pickles it as a member of the base class,
          is that it?

          i don't know how i would get around the problem, though, because i'd have to
          know how to access the deque object that my class stores when i do
          deque.__init__ in my constructor, so that i could pickle it and my class
          variables separately.




          "Larry Bates" <larry.bates@we bsafe.com`wrote in message
          news:0uednUCD-McN-a7VnZ2dnUVZ_tzi nZ2d@comcast.co m...
          inhahe wrote:
          > def __init__(self, filename, initial):
          >>
          >should be
          >>
          > def __init__(self, filename, initial=[]):
          >>
          >(that was the whole reason i put the filename first.)
          >>
          >sorry.
          >>
          >>
          >>
          Defaulting initial to empty list this way is asking for trouble. You
          should
          default it to None and check for None and reset to empty list.
          >
          -Larry

          Comment

          • inhahe

            #6
            Re: persistent deque

            >
            i don't know how i would get around the problem, though, because i'd have
            to know how to access the deque object that my class stores when i do
            deque.__init__ in my constructor, so that i could pickle it and my class
            variables separately.
            >
            >
            i decided i could just pickle deque(self), which should return a regular
            deque object with the data from self, and then in the load routine make a
            pdeque object from it.

            that, of couse, gives me another error. 'collections.de que' object has no
            attribute 'write'. from the line 'self.write = file.write', which is in
            pickle.py
            pickling list(self) doesnt work either.





            Comment

            • inhahe

              #7
              Re: persistent deque

              something randomly made me realize why my second solution didn't work, so i
              fixed it. now you have a working persistent deque.

              1. if you call somepdequeobjec t.load(filename ) (as opposed to
              pdeque.load(fil ename)), do you want it to return a new object that it loaded
              from file, or do you want it to change somepdequeobjec t to be the object in
              the file? i'm not sure which way is canonical.

              2. i'm not sure if i actually have to use a temp file and then copy it. i
              don't know if pickle.dump as an "atomic commit".

              3. cPickle would be faster but i think that means you might end up storing
              something in your deque that can't be pickled, like a circular reference,
              and dunno what else.

              4. can someone tell me if the way i'm using the decorator is sane? i've
              never used decorators before. it just seems ridiculous to a) define a lambda
              that just throws away the parameter, and b) define a meaningless function to
              pass to that lambda.

              5. Of course, I am a genius.

              from collections import deque
              import os, pickle, random

              class pdeque(deque):
              def __init__(self, filename, initial=None):
              if initial is None: initial = []
              deque.__init__( self, initial)
              self.filename = filename
              self.tempfilena me = ''.join((random .choice("abcdef ghijklmnopqrstu vwxyz")
              for x in xrange(10)))+". tmp"
              self.save()
              def save(self):
              pickle.dump(deq ue(self), open(self.tempf ilename,'wb'))
              try: os.remove(self. filename)
              except: pass
              os.rename(self. tempfilename, self.filename)
              @classmethod
              def load(cls, filename):
              return pdeque(filename , pickle.load(ope n(filename,'rb' )))

              #todo: change this so that if it's called from an object it loads
              #the data into that object?

              def makefunc(func):
              def func2(instance, *args):
              result = func(instance, *args)
              instance.save()
              return result
              return lambda _: func2

              for name, func in deque.__dict__. items():
              if (not name.startswith ("_")) or name in ('__delitem__', '__setitem__'):
              @makefunc(func)
              def f(): pass
              setattr(pdeque, name, f)







              "castironpi " <castironpi@gma il.comwrote in message
              news:29451c2a-cb0a-43a6-b140-6c16e3cb46ac@c6 5g2000hsa.googl egroups.com...
              I'd like a persistent deque, such that the instance operations all
              commit atomicly to file system.

              Comment

              • inhahe

                #8
                Re: persistent deque version 4


                "inhahe" <inhahe@gmail.c omwrote in message
                news:XF1Zj.7828 7$%15.22707@big news7.bellsouth .net...
                >
                4. can someone tell me if the way i'm using the decorator is sane? i've
                never used decorators before. it just seems ridiculous to a) define a
                lambda that just throws away the parameter, and b) define a meaningless
                function to pass to that lambda.
                >

                I thought about the fact that a decorator is merely syntactic sugar, so it
                shouldn't have any closure magic that I can't make myself, and I realized
                that I could have done it the following way:

                def makefunc(func):
                def func2(instance, *args):
                result = func(instance, *args)
                instance.save()
                return result
                return func2

                for name, func in deque.__dict__. items():
                if (not name.startswith ("_")) or name in ('__delitem__', '__setitem__'):
                setattr(pdeque, name, makefunc(func))



                Comment

                • Gabriel Genellina

                  #9
                  Re: persistent deque version 4

                  En Thu, 22 May 2008 12:20:56 -0300, inhahe <inhahe@gmail.c omescribió:
                  I thought about the fact that a decorator is merely syntactic sugar, so it
                  shouldn't have any closure magic that I can't make myself, and I realized
                  that I could have done it the following way:
                  >
                  def makefunc(func):
                  def func2(instance, *args):
                  result = func(instance, *args)
                  instance.save()
                  return result
                  return func2
                  Using functools.wraps is better because it helps to preserve the function name and signature:

                  def makefunc(func):
                  @wraps(func)
                  def wrapper(self, *args, **kwds):
                  result = func(self, *args, **kwds)
                  self.save()
                  return result
                  return wrapper

                  --
                  Gabriel Genellina

                  Comment

                  Working...