Returning other instance from __init__

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Paulo da Silva

    #1

    Returning other instance from __init__

    I would like to implement something like this:

    class C1:
    def __init__(self,x xx):
    if ... :
    self.foo = foo
    self.bar = bar
    else:
    self=C1.load(xx x)

    def load(xxx):
    ...
    return instance_of_C1
    load=staticmeth od(load)

    This does not seem correct. How can I do it?

    Thanks for any help
    Paulo
  • Alex Martelli

    #2
    Re: Returning other instance from __init__

    Paulo da Silva <psdasilvaX@eso tericaX.ptXwrot e:
    I would like to implement something like this:
    >
    class C1:
    def __init__(self,x xx):
    if ... :
    self.foo = foo
    self.bar = bar
    else:
    self=C1.load(xx x)
    >
    def load(xxx):
    ...
    return instance_of_C1
    load=staticmeth od(load)
    >
    This does not seem correct. How can I do it?
    Use __new__ for such purposes, not __init__. (You need to make C1
    newstyle, e.g. inherit from object, to make special method __new__
    work).

    From __new__ you can return whatever you wish. However, if you return
    an instance of C1, it _will_ be passed to __init__; so, just make sure
    __init__ doesn't redo the initialization if passed an
    already-initialized self.

    E.g.:

    class C1(object):
    def __new__(cls, xxx):
    if xxx: return type.__new__(cl s, xxx)
    else: return C1.load(xxx)
    @staticmethod
    def load(xxx): return ...whatever...
    def __init__(self, xxx):
    if hasattr(self, 'foo'): return
    self.foo = 'foo'
    self.bar = 'bar'


    Alex

    Comment

    • Paul Boddie

      #3
      Re: Returning other instance from __init__

      On 15 Mar, 06:21, a...@mac.com (Alex Martelli) wrote:
      Paulo da Silva <psdasil...@eso tericaX.ptXwrot e:

      I would like to implement something like this:

      class C1:
      def __init__(self,x xx):
      if ... :
      self.foo = foo
      self.bar = bar
      else:
      self=C1.load(xx x)

      def load(xxx):
      ...
      return instance_of_C1
      load=staticmeth od(load)

      This does not seem correct. How can I do it?
      >
      Use __new__ for such purposes, not __init__. (You need to make C1
      newstyle, e.g. inherit from object, to make special method __new__
      work).
      Call me a traditionalist, but why wouldn't a factory function be good
      enough?

      def C1(xxx):
      if ...:
      return the_real_C1()
      else:
      return load(xxx)

      def load(xxx):
      ...
      return instance_of_C1

      Or perhaps seeing more special methods and decorators just puts me in
      a grumpy mood. ;-) For me, the power of Python is derived from being
      able to do things like making callables "constructo rs" whilst
      providing some illusion that C1 (in this case) is a class.

      Paul

      Comment

      • Alex Martelli

        #4
        Re: Returning other instance from __init__

        Paul Boddie <paul@boddie.or g.ukwrote:
        ...
        class C1:
        def __init__(self,x xx):
        ...
        Use __new__ for such purposes, not __init__. (You need to make C1
        newstyle, e.g. inherit from object, to make special method __new__
        work).
        >
        Call me a traditionalist, but why wouldn't a factory function be good
        enough?
        That depends on whether you need name C1 to refer to a class, or not.

        If you want name C1 to be usable outside this module as a class (to
        subclass it, use with isinstance or issubclass, be available to an IDE's
        classbrowser or other means of introspection including pydoc, etc), then
        making name C1 refer to a function instead would not work.
        Or perhaps seeing more special methods and decorators just puts me in
        a grumpy mood. ;-) For me, the power of Python is derived from being
        able to do things like making callables "constructo rs" whilst
        providing some illusion that C1 (in this case) is a class.
        For me, OTOH, it's not just smoke and mirrors (or as you say
        "illusion") , there's also plenty of real power, and __new__ is part of
        that. (Decorators however are just handy syntax -- they let you avoid
        repeating one name three times, and avoiding repetition is a good thing,
        but their real power is essentially that of higher-order-functions that
        could of course be used with other syntax if need be).


        Alex

        Comment

        • Paulo da Silva

          #5
          Re: Returning other instance from __init__

          Alex Martelli escreveu:
          Paulo da Silva <psdasilvaX@eso tericaX.ptXwrot e:
          ....
          >
          E.g.:
          >
          class C1(object):
          def __new__(cls, xxx):
          if xxx: return type.__new__(cl s, xxx)
          else: return C1.load(xxx)
          @staticmethod
          def load(xxx): return ...whatever...
          def __init__(self, xxx):
          if hasattr(self, 'foo'): return
          self.foo = 'foo'
          self.bar = 'bar'
          >

          Just for a better understanding ...
          Can I do this?

          class C1(object):
          def __new__(cls, xxx):
          if xxx:
          cls.foo='foo'
          cls.bar='bar'
          return type.__new__(cl s, xxx)
          else:
          return C1.load(xxx)
          @staticmethod
          def load(xxx): return ...whatever...
          # OMMIT THE __init__
          # or
          def __init__(self, xxx):
          pass

          Comment

          • Paul Boddie

            #6
            Re: Returning other instance from __init__

            On 15 Mar, 15:50, a...@mac.com (Alex Martelli) wrote:
            Paul Boddie <p...@boddie.or g.ukwrote:
            Call me a traditionalist, but why wouldn't a factory function be good
            enough?
            >
            That depends on whether you need name C1 to refer to a class, or not.
            Right.
            If you want name C1 to be usable outside this module as a class (to
            subclass it, use with isinstance or issubclass, be available to an IDE's
            classbrowser or other means of introspection including pydoc, etc), then
            making name C1 refer to a function instead would not work.
            True. I can easily buy the argument about wanting to subclass C1,
            although you'd always have the real class available somewhere as well.
            For things like IDEs, class browsers and so on, I think more work
            needs to be done to make these things more "aware" - it sounds like
            they expect a more rigid language (like Java), but I do have some
            awareness of why it's tempting to let them operate on their current
            level of introspection.
            Or perhaps seeing more special methods and decorators just puts me in
            a grumpy mood. ;-) For me, the power of Python is derived from being
            able to do things like making callables "constructo rs" whilst
            providing some illusion that C1 (in this case) is a class.
            >
            For me, OTOH, it's not just smoke and mirrors (or as you say
            "illusion") , there's also plenty of real power, and __new__ is part of
            that.
            Oh, I like the illusion! The illusion is what makes Python so
            powerful, after all.

            Paul

            Comment

            • Alex Martelli

              #7
              Re: Returning other instance from __init__

              Paulo da Silva <psdasilvaX@eso tericaX.ptXwrot e:
              Alex Martelli escreveu:
              Paulo da Silva <psdasilvaX@eso tericaX.ptXwrot e:
              ...
              >

              E.g.:

              class C1(object):
              def __new__(cls, xxx):
              if xxx: return type.__new__(cl s, xxx)
              else: return C1.load(xxx)
              @staticmethod
              def load(xxx): return ...whatever...
              def __init__(self, xxx):
              if hasattr(self, 'foo'): return
              self.foo = 'foo'
              self.bar = 'bar'
              >
              >
              Just for a better understanding ...
              Can I do this?
              >
              class C1(object):
              def __new__(cls, xxx):
              if xxx:
              cls.foo='foo'
              cls.bar='bar'
              return type.__new__(cl s, xxx)
              else:
              return C1.load(xxx)
              @staticmethod
              def load(xxx): return ...whatever...
              # OMMIT THE __init__
              # or
              def __init__(self, xxx):
              pass
              Yes (omitting the __init__ is better than having it empty), but why do
              you want to alter the class object itself, rather than the INSTANCE
              you're returning?

              I suspect what you really want to do is rather

              if xxx:
              newobj = type.__new__(cl s)
              newobj.foo = 'foo'
              newobj.bar = 'bar'
              return newobj
              else ...etc etc...

              altering the _instance_ and not the _class_ itself.


              Alex

              Comment

              • Paulo da Silva

                #8
                Re: Returning other instance from __init__

                Paulo da Silva escreveu:
                Alex Martelli escreveu:
                >Paulo da Silva <psdasilvaX@eso tericaX.ptXwrot e:
                ....
                >
                >E.g.:
                >>
                >class C1(object):
                > def __new__(cls, xxx):
                > if xxx: return type.__new__(cl s, xxx)
                > else: return C1.load(xxx)
                > @staticmethod
                > def load(xxx): return ...whatever...
                > def __init__(self, xxx):
                > if hasattr(self, 'foo'): return
                > self.foo = 'foo'
                > self.bar = 'bar'
                >>
                >
                >
                Just for a better understanding ...
                Can I do this?
                >
                class C1(object):
                def __new__(cls, xxx):
                if xxx:
                cls.foo='foo'
                cls.bar='bar'
                return type.__new__(cl s, xxx)
                This does not work(!) at least for python 2.4.3.
                else:
                return C1.load(xxx)
                @staticmethod
                def load(xxx): return ...whatever...
                # OMMIT THE __init__
                # or
                def __init__(self, xxx):
                pass
                I needed return cls and put the __init__ stuff here.
                Is this the best practice?

                Thanks.

                Comment

                • Paulo da Silva

                  #9
                  Re: Returning other instance from __init__ - I need help

                  Paulo da Silva escreveu:
                  Paulo da Silva escreveu:
                  >Alex Martelli escreveu:
                  >>Paulo da Silva <psdasilvaX@eso tericaX.ptXwrot e:
                  >....
                  >>
                  >>E.g.:
                  >>>
                  >>class C1(object):
                  >> def __new__(cls, xxx):
                  >> if xxx: return type.__new__(cl s, xxx)
                  >> else: return C1.load(xxx)
                  >> @staticmethod
                  >> def load(xxx): return ...whatever...
                  >> def __init__(self, xxx):
                  >> if hasattr(self, 'foo'): return
                  >> self.foo = 'foo'
                  >> self.bar = 'bar'
                  >>>
                  >>
                  >Just for a better understanding ...
                  >Can I do this?
                  >>
                  >class C1(object):
                  > def __new__(cls, xxx):
                  > if xxx:
                  > cls.foo='foo'
                  > cls.bar='bar'
                  > return type.__new__(cl s, xxx)
                  This does not work(!) at least for python 2.4.3.
                  >
                  > else:
                  > return C1.load(xxx)
                  > @staticmethod
                  > def load(xxx): return ...whatever...
                  > # OMMIT THE __init__
                  > # or
                  > def __init__(self, xxx):
                  > pass
                  >
                  I needed return cls and put the __init__ stuff here.
                  Is this the best practice?
                  >
                  When debugging, I found this is wrong!!!
                  Would someone please clarify what do I have to return from
                  __new__?

                  Thank you very much.


                  Comment

                  • Steven D'Aprano

                    #10
                    Re: Returning other instance from __init__

                    On Thu, 15 Mar 2007 04:33:01 +0000, Paulo da Silva wrote:
                    I would like to implement something like this:
                    >
                    class C1:
                    def __init__(self,x xx):
                    if ... :
                    self.foo = foo
                    self.bar = bar
                    else:
                    self=C1.load(xx x)
                    >
                    def load(xxx):
                    ...
                    return instance_of_C1
                    load=staticmeth od(load)
                    >
                    This does not seem correct. How can I do it?


                    Others have come up with other solutions which may or may not work, but
                    perhaps you can adapt this to do what you want.


                    class CachedClass(obj ect):
                    """Class that recycles cached instances.
                    """
                    _cache = {}
                    def __new__(cls, ID):
                    print "Calling constructor __new__ ..."
                    if cls._cache.has_ key(ID):
                    print "Returning cached instance..."
                    return cls._cache[ID]
                    else:
                    print "Creating new instance..."
                    obj = super(CachedCla ss, cls).__new__(cl s, ID)
                    cls._cache[ID] = obj
                    return obj
                    def __init__(self, ID):
                    print "Calling constructor __init__ ..."
                    self.ID = ID



                    --
                    Steven

                    Comment

                    • Gabriel Genellina

                      #11
                      Re: Returning other instance from __init__ - I need help

                      En Fri, 16 Mar 2007 22:05:05 -0300, Paulo da Silva
                      <psdasilvaX@eso tericaX.ptXescr ibió:
                      When debugging, I found this is wrong!!!
                      Would someone please clarify what do I have to return from
                      __new__?
                      Try this. I used a classmethod for load, it may be easier to subclass.

                      class C(object):

                      def __new__(cls, filename=None, foo=None, bar=None):
                      if filename is not None:
                      return cls.load(filena me)
                      inst = super(C, cls).__new__(cl s)
                      inst.foo = foo
                      inst.bar = bar
                      return inst

                      @classmethod
                      def load(cls, filename):
                      inst = super(C, cls).__new__(cl s)
                      inst.foo = "some foo loaded from "+filename
                      inst.bar = "some bar loaded from "+filename
                      return inst

                      class D(C):
                      @classmethod
                      def load(cls, filename):
                      inst = super(D, cls).__new__(cl s)
                      inst.foo = "D foo loaded from "+filename
                      inst.bar = "D bar loaded from "+filename
                      return inst


                      c1 = C(foo=1, bar=2)
                      print "c1=", c1
                      print "c1.foo=", c1.foo
                      print "c1.bar=", c1.bar
                      c2 = C(filename="xxx .txt")
                      print "c2=", c2
                      print "c2.foo=", c2.foo
                      print "c2.bar=", c2.bar

                      d1 = D(foo=10, bar=20)
                      print "d1=", d1
                      print "d1.foo=", d1.foo
                      print "d1.bar=", d1.bar
                      d2 = D(filename="yyy .txt")
                      print "d2=", d2
                      print "d2.foo=", d2.foo
                      print "d2.bar=", d2.bar


                      --
                      Gabriel Genellina

                      Comment

                      • Paulo da Silva

                        #12
                        Re: Returning other instance from __init__ - I need help

                        Gabriel Genellina escreveu:
                        En Fri, 16 Mar 2007 22:05:05 -0300, Paulo da Silva
                        <psdasilvaX@eso tericaX.ptXescr ibió:
                        ....
                        class C(object):
                        >
                        def __new__(cls, filename=None, foo=None, bar=None):
                        if filename is not None:
                        return cls.load(filena me)
                        inst = super(C, cls).__new__(cl s)

                        This makes the difference! I didn't know how to "build" an
                        instance inside __new__.

                        Thank you very much Gabriel.
                        Paulo

                        Comment

                        Working...