singleton objects with decorators

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

    #16
    Re: singleton objects with decorators

    Tuesday 12 April 2005 14:51 pm Michele Simionato wrote:
    [color=blue]
    > No. Not everybody knows about Singleton. It is an acquired knowledge.[/color]

    Well, what isn't?
    What I ment to say, but failed to do so more explicitly, was that it is a
    term I felt which was generally known to "the programming society". Or that
    it is a term that might pop up in a comunity where software design is an
    issue.
    This of course does not mean that you could not have used it without knowing
    that someone had thought of a fancy name for it.

    [...][color=blue]
    > It was only after many months that I understood that there was really
    > nothing
    > more to it.[/color]

    I agree. There really isn't much to Singletons. There was a time when I also
    did not know about Singletons or design pattern in general. But thats
    always the case somehow, somewhere.

    [...][color=blue]
    > In my lectures at Oxford next week I have carefully expunged anything
    > referring to Singletons ;)[/color]

    Perhapts you shouldn't. Otherwise people might stumble over the same problem
    you did.
    [color=blue]
    > IMNSHO, the property "there is only one" is not important enough to
    > deserves
    > a name.[/color]

    The problem here is: it has already a name. It is the probably most simple
    pattern there is. And if only it serves as a mind-boggingly example of a
    design pattern, why not call it a "singleton" . Why call it a "class that
    can only be instanciated once"?
    I do not yet feel there is being made too much fuss about it. People do not
    start name-dropping on singletons. Design pattern in general, perhaps.
    [color=blue]
    > The property "if you have already called this callable with the
    > same arguments you don't need to recompute it" instead is quite worthy
    > and subsumes the other concept as a special case. It also gives you
    > plenty of use case to illustrate it, even to beginner programmers.[/color]

    To step in your argument, you could also call that "caching a function
    call".

    BTW: @memoize on the __new__ method isn't quite enough. You'll have to call
    it on __init__ as well, otherwise it is executed again on the already
    initialised object.
    Also calling @memoize on the __init__ does not suffice either, because can
    call it with different parameters...

    Ciao
    Uwe

    Comment

    • Steven Bethard

      #17
      Re: singleton objects with decorators

      Fredrik Lundh wrote:[color=blue]
      > Or if you're using an application object (you should), just add a config object
      > to the application object (app.config.par am = ...).[/color]

      Do you have a link or two that describe what you mean by an "applicatio n
      object"? The "you should" comment makes me think this is something of a
      design pattern, but googling around wasn't able to satisfy my curiosity.

      STeVe

      Comment

      • Steven Bethard

        #18
        Re: singleton objects with decorators

        Uwe Mayer wrote:[color=blue]
        > Tuesday 12 April 2005 10:01 am Steven Bethard wrote:
        >[color=green][color=darkred]
        >>>I am using a class to manage configuration settings in an application.
        >>>This object should only existe once so that when the user
        >>>changes a setting through a configuration dialog the change imminent in
        >>>all locations where access to config settings are needed.[/color][/color]
        >[color=green]
        >>Ahh, I see. I would typically just use a module in this situation,
        >>where the configuration settings were just names global to the module.
        >>Is there a benefit to using a singleton object over using just a module?[/color]
        >
        > Basically I am using a module. The config file is stored in
        > $HOME/.<app>/<app>.conf where the user can go and edit it. It is a working
        > python program which globally declares variables.
        > I cannot simply import this module as it does not lie in the path and I am
        > not too fond of dynamically cluttering sys.path to my needs.[/color]

        Hmmm... Maybe you could use a memoized wrapper to imp.load_source ?
        I've never used it, but it looks kinda like it might do what you want...

        But I guess that probably doesn't really gain you too much over the
        Singleton solution...

        STeVe

        Comment

        • Michele Simionato

          #19
          Re: singleton objects with decorators

          I did not put memoize on __new__. I put it on the metaclass __call__.
          Here is my memoize:

          def memoize(func):
          memoize_dic = {}
          def wrapped_func(*a rgs):
          if args in memoize_dic:
          return memoize_dic[args]
          else:
          result = func(*args)
          memoize_dic[args] = result
          return result
          wrapped_func.__ name__ = func.__name__
          wrapped_func.__ doc__ = func.__doc__
          wrapped_func.__ dict__ = func.__dict__
          return wrapped_func

          class Memoize(type): # Singleton is a special case of Memoize
          @memoize
          def __call__(cls, *args):
          return super(Memoize, cls).__call__(* args)

          Comment

          • Uwe Mayer

            #20
            Re: singleton objects with decorators

            Tuesday 12 April 2005 17:00 pm Michele Simionato wrote:
            [color=blue]
            > I did not put memoize on __new__. I put it on the metaclass __call__.
            > Here is my memoize:[/color]
            [...]

            Clever, thanks! :)

            Ciao
            Uwe

            Comment

            • Uwe Mayer

              #21
              Re: singleton objects with decorators

              Tuesday 12 April 2005 17:00 pm Michele Simionato wrote:
              [color=blue]
              > I did not put memoize on __new__. I put it on the metaclass __call__.
              > Here is my memoize:
              >
              > def memoize(func):
              > memoize_dic = {}
              > def wrapped_func(*a rgs):
              > if args in memoize_dic:
              > return memoize_dic[args]
              > else:
              > result = func(*args)
              > memoize_dic[args] = result
              > return result
              > wrapped_func.__ name__ = func.__name__
              > wrapped_func.__ doc__ = func.__doc__
              > wrapped_func.__ dict__ = func.__dict__
              > return wrapped_func
              >
              > class Memoize(type): # Singleton is a special case of Memoize
              > @memoize
              > def __call__(cls, *args):
              > return super(Memoize, cls).__call__(* args)[/color]

              I tried it out and found the following "inconsistency" :
              [color=blue][color=green][color=darkred]
              >>> class Foobar(object):[/color][/color][/color]
              .... __metaclass__ = Memoize
              .... def __init__(self, *args): pass
              ....[color=blue][color=green][color=darkred]
              >>> Foobar(1)[/color][/color][/color]
              <__main__.Fooba r object at 0x4006f7ec>[color=blue][color=green][color=darkred]
              >>> Foobar(2)[/color][/color][/color]
              <__main__.Fooba r object at 0x4006f7cc>[color=blue][color=green][color=darkred]
              >>> Foobar(3)[/color][/color][/color]
              <__main__.Fooba r object at 0x4006f82c>

              Unless I'm using it incorrectly (I haven't done much metaclass programming
              yet) this is the same problem was with using @memoize on __new__ and
              __init__.

              Talking so much about singletons I'm not even sure what the definition on
              calling a singleton with different constructor parameter values is.

              Anyways, a fix for that could be:

              class SingletonFactor y(type):
              single = {}
              def __call__(cls, *args):
              if (cls not in SingletonFactor y.single):
              SingletonFactor y.single[cls] = super(Singleton Factory,
              cls).__call__(* args)
              return SingletonFactor y.single[cls]


              i.e. not caching the parameter values or types.

              Uwe

              Comment

              • Michele Simionato

                #22
                Re: singleton objects with decorators

                Uhm? If I pass different parameters I want to have
                different instances. The Singleton behaviour is recovered
                only when I pass always the same arguments, in
                particular when I pass 0-arguments:
                [color=blue][color=green][color=darkred]
                >>> class Foobar:[/color][/color][/color]
                .... __metaclass__ = Memoize
                ....[color=blue][color=green][color=darkred]
                >>> Foobar()[/color][/color][/color]
                <__main__.Fooba r object at 0xb7defbcc>[color=blue][color=green][color=darkred]
                >>> Foobar()[/color][/color][/color]
                <__main__.Fooba r object at 0xb7defbcc>[color=blue][color=green][color=darkred]
                >>> Foobar()[/color][/color][/color]
                <__main__.Fooba r object at 0xb7defbcc>

                Of course if for Singleton you mean "whatever I pass
                to the constructor it must always return the same
                instance" then this pattern is not a Singleton.
                This is why I call it memoize ;)

                Comment

                • Uwe Mayer

                  #23
                  Re: singleton objects with decorators

                  Tuesday 12 April 2005 18:51 pm Michele Simionato wrote:
                  [color=blue]
                  > Uhm? If I pass different parameters I want to have
                  > different instances. The Singleton behaviour is recovered
                  > only when I pass always the same arguments, in
                  > particular when I pass 0-arguments:
                  >[color=green][color=darkred]
                  >>>> class Foobar:[/color][/color]
                  > ... __metaclass__ = Memoize
                  > ...[color=green][color=darkred]
                  >>>> Foobar()[/color][/color]
                  > <__main__.Fooba r object at 0xb7defbcc>[color=green][color=darkred]
                  >>>> Foobar()[/color][/color]
                  > <__main__.Fooba r object at 0xb7defbcc>[color=green][color=darkred]
                  >>>> Foobar()[/color][/color]
                  > <__main__.Fooba r object at 0xb7defbcc>
                  >
                  > Of course if for Singleton you mean "whatever I pass
                  > to the constructor it must always return the same
                  > instance" then this pattern is not a Singleton.
                  > This is why I call it memoize ;)[/color]

                  :)

                  I guess it depends on what you want to do with the instance and the
                  constructor, wether it satisfies the condition to be a "singleton" :

                  If you pass i.e. the timestamp of object creation in the constructor, or the
                  class name that instanciates the object, a memoized implementation would
                  not suffice.

                  On the other hand if you need parameterized implementations of a singleton,
                  i.e. for each colour 'red', 'green', 'blue' - then a memoized
                  implementation would be better.

                  Uwe

                  Comment

                  • Steve Holden

                    #24
                    Re: singleton objects with decorators

                    Bengt Richter wrote:
                    [...][color=blue]
                    > It's a weird beast, being a subtype of int also. I'll defer to the BDFL in
                    > http://www.python.org/peps/pep-0285.html
                    >
                    > """
                    > The values False and True will be singletons, like None. Because
                    > the type has two values, perhaps these should be called
                    > "doubletons "? The real implementation will not allow other
                    > instances of bool to be created.
                    > """
                    >
                    > Regards,
                    > Bengt Richter[/color]

                    It would probably make sense (IMHO) to deny rebinding of True and False
                    in the same way that 2.4 denies rebinding of None. Given that people
                    would set True and False themselves in order to make their pre-2.4 code
                    readable, however, this may overstress backward compatibility.

                    regards
                    Steve
                    --
                    Steve Holden +1 703 861 4237 +1 800 494 3119
                    Holden Web LLC http://www.holdenweb.com/
                    Python Web Programming http://pydish.holdenweb.com/

                    Comment

                    • Bengt Richter

                      #25
                      Re: singleton objects with decorators

                      On 12 Apr 2005 08:00:42 -0700, "Michele Simionato" <michele.simion ato@gmail.com> wrote:
                      [color=blue]
                      >I did not put memoize on __new__. I put it on the metaclass __call__.
                      >Here is my memoize:
                      >
                      > def memoize(func):
                      > memoize_dic = {}
                      > def wrapped_func(*a rgs):
                      > if args in memoize_dic:
                      > return memoize_dic[args]
                      > else:
                      > result = func(*args)
                      > memoize_dic[args] = result
                      > return result
                      > wrapped_func.__ name__ = func.__name__
                      > wrapped_func.__ doc__ = func.__doc__
                      > wrapped_func.__ dict__ = func.__dict__
                      > return wrapped_func
                      >
                      > class Memoize(type): # Singleton is a special case of Memoize
                      > @memoize
                      > def __call__(cls, *args):
                      > return super(Memoize, cls).__call__(* args)
                      >[/color]
                      Thanks, that is nice and simple, though caching instances of a class
                      according to initialization parameters is not quite the same concept
                      as singleton instances, I think. OTOH, if you want to pass differing
                      parameters to the same instance of a class, there are lots of methods
                      (pun ;-) to do that that are clearer than (ab)using the constructor interface.
                      I.e., what is the difference between shared access to a callable instance
                      in a module vs shared access to a strange class in the same place?

                      Hm, just had a thought re memoize: you could give it its own optional
                      hashing function as a keyword argument, and let it use that as a key
                      for memoize_dic. Then you could use that to make a singleton(-making) class
                      or a dual/doubleton-making class like bool, e.g., Bool below

                      ----< memoize.py >--------------------------------------------------------
                      def memoize(arghash =lambda args:args, method=False):
                      def _memoize(func):
                      memoize_dic = {}
                      def wrapped_func(*a rgs):
                      key = arghash(args[method:])
                      if key in memoize_dic:
                      return memoize_dic[key]
                      else:
                      result = func(*args)
                      memoize_dic[key] = result
                      return result
                      wrapped_func.__ name__ = func.__name__
                      wrapped_func.__ doc__ = func.__doc__
                      wrapped_func.__ dict__ = func.__dict__
                      return wrapped_func
                      return _memoize

                      def mkPolyton(argha sh=lambda args:args):
                      class Memoize(type): # Singleton is a special case of Memoize
                      @memoize(arghas h, True) # (with arghash=lambda args:0 -> singleton)
                      def __call__(cls, *args):
                      return super(Memoize, cls).__call__(* args)
                      return Memoize

                      class Bool(int):
                      __metaclass__ = mkPolyton(lambd a args:args and args[0] and 1 or 0)
                      def __repr__(self): return ('False', 'True')[self]
                      __str__ = __repr__

                      def tests(todo):
                      if '1' in todo:
                      @memoize()
                      def square(x): return x*x
                      print '[id(square(1234) )...]: ten have same id:', [id(square(1234) )
                      for x in xrange(10)].count(id(squar e(1234))) == 10
                      if '2' in todo:
                      F = Bool(0) # init cache with proper False value
                      T = Bool(1) # ditto for True value
                      print 'T:', T, id(T)
                      print 'F:', F, id(F)
                      print '[id(Bool(1..10)) ...]: ten have same id:', [id(Bool(x))
                      for x in xrange(1,11)].count(id(T)) == 10

                      if __name__ == '__main__':
                      import sys
                      tests(sys.argv[1:])
                      --------------------------------------------------------------------------
                      Result (not exactly a thorough test ;-):

                      [16:36] C:\pywk\ut>py24 memoize.py 1 2
                      [id(square(1234) )...]: ten have same id: True
                      T: True 49271436
                      F: False 49271884
                      [id(Bool(1..10)) ...]: ten have same id: True

                      BTW, I found this page interesting:



                      Regards,
                      Bengt Richter

                      Comment

                      • James Stroud

                        #26
                        Re: singleton objects with decorators

                        Other than using modules, I thought @classmethod took care of this kind of
                        need:

                        class SingleThing:
                        some_values = {"fanciness" :0}
                        def __init__(self):
                        raise Exception, "not enough preceding stars to be fancy enough"
                        @classmethod
                        def why_so_fancy(se lf):
                        print "why make every thing so fancy?"

                        I call this pattern:

                        "Using a Class to Be Something Single Because It Already Is Single"

                        or "uactbssbia is", for short.

                        James

                        --
                        James Stroud, Ph.D.
                        UCLA-DOE Institute for Genomics and Proteomics
                        Box 951570
                        Los Angeles, CA 90095


                        Comment

                        • Steven Bethard

                          #27
                          Re: singleton objects with decorators

                          James Stroud wrote:[color=blue]
                          > Other than using modules, I thought @classmethod took care of this kind of
                          > need:
                          >
                          > class SingleThing:
                          > some_values = {"fanciness" :0}
                          > def __init__(self):
                          > raise Exception, "not enough preceding stars to be fancy enough"
                          > @classmethod
                          > def why_so_fancy(se lf):
                          > print "why make every thing so fancy?"
                          >
                          > I call this pattern:
                          >
                          > "Using a Class to Be Something Single Because It Already Is Single"
                          >
                          > or "uactbssbia is", for short.[/color]

                          +1 VOTW (Vocabulation of the Week)

                          =)

                          STeVe

                          Comment

                          Working...