Returning other instance from __init__

Discussion in 'Python' started by Paulo da Silva, Mar 15, 2007.

  1. I would like to implement something like this:

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

    def load(xxx):
    ...
    return instance_of_C1
    load=staticmethod(load)

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

    Thanks for any help
    Paulo
     
    Paulo da Silva, Mar 15, 2007
    #1
    1. Advertising

  2. Paulo da Silva <> wrote:

    > I would like to implement something like this:
    >
    > class C1:
    > def __init__(self,xxx):
    > if ... :
    > self.foo = foo
    > self.bar = bar
    > else:
    > self=C1.load(xxx)
    >
    > def load(xxx):
    > ...
    > return instance_of_C1
    > load=staticmethod(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__(cls, 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
     
    Alex Martelli, Mar 15, 2007
    #2
    1. Advertising

  3. On Thu, 15 Mar 2007 04:33:01 +0000, Paulo da Silva
    <> declaimed the following in comp.lang.python:

    > I would like to implement something like this:
    >
    > class C1:
    > def __init__(self,xxx):
    > if ... :
    > self.foo = foo
    > self.bar = bar
    > else:
    > self=C1.load(xxx)
    >
    > def load(xxx):
    > ...
    > return instance_of_C1
    > load=staticmethod(load)
    >
    > This does not seem correct. How can I do it?
    >

    You can't do it with __init__()...

    __init__() only INITIALIZES attributes of an object (self, passed
    in) that is created by __new__().
    --
    Wulfraed Dennis Lee Bieber KD6MOG

    HTTP://wlfraed.home.netcom.com/
    (Bestiaria Support Staff: )
    HTTP://www.bestiaria.com/
     
    Dennis Lee Bieber, Mar 15, 2007
    #3
  4. Paulo da Silva

    Paul Boddie Guest

    On 15 Mar, 06:21, (Alex Martelli) wrote:
    > Paulo da Silva <> wrote:
    > >
    > > I would like to implement something like this:
    > >
    > > class C1:
    > > def __init__(self,xxx):
    > > if ... :
    > > self.foo = foo
    > > self.bar = bar
    > > else:
    > > self=C1.load(xxx)
    > >
    > > def load(xxx):
    > > ...
    > > return instance_of_C1
    > > load=staticmethod(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 "constructors" whilst
    providing some illusion that C1 (in this case) is a class.

    Paul
     
    Paul Boddie, Mar 15, 2007
    #4
  5. Paul Boddie <> wrote:
    ...
    > > > class C1:
    > > > def __init__(self,xxx):

    ...
    > > 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 "constructors" 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
     
    Alex Martelli, Mar 15, 2007
    #5
  6. Alex Martelli escreveu:
    > Paulo da Silva <> wrote:

    ....

    >
    > E.g.:
    >
    > class C1(object):
    > def __new__(cls, xxx):
    > if xxx: return type.__new__(cls, 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__(cls, xxx)
    else:
    return C1.load(xxx)
    @staticmethod
    def load(xxx): return ...whatever...
    # OMMIT THE __init__
    # or
    def __init__(self, xxx):
    pass
     
    Paulo da Silva, Mar 15, 2007
    #6
  7. Paulo da Silva

    Paul Boddie Guest

    On 15 Mar, 15:50, (Alex Martelli) wrote:
    > Paul Boddie <> wrote:
    > > 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 "constructors" 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
     
    Paul Boddie, Mar 15, 2007
    #7
  8. Paulo da Silva <> wrote:

    > Alex Martelli escreveu:
    > > Paulo da Silva <> wrote:

    > ...
    >
    > >
    > > E.g.:
    > >
    > > class C1(object):
    > > def __new__(cls, xxx):
    > > if xxx: return type.__new__(cls, 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__(cls, 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__(cls)
    newobj.foo = 'foo'
    newobj.bar = 'bar'
    return newobj
    else ...etc etc...

    altering the _instance_ and not the _class_ itself.


    Alex
     
    Alex Martelli, Mar 16, 2007
    #8
  9. Paulo da Silva escreveu:
    > Alex Martelli escreveu:
    >> Paulo da Silva <> wrote:

    > ....
    >
    >> E.g.:
    >>
    >> class C1(object):
    >> def __new__(cls, xxx):
    >> if xxx: return type.__new__(cls, 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__(cls, 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.
     
    Paulo da Silva, Mar 16, 2007
    #9
  10. Re: Returning other instance from __init__ - I need help

    Paulo da Silva escreveu:
    > Paulo da Silva escreveu:
    >> Alex Martelli escreveu:
    >>> Paulo da Silva <> wrote:

    >> ....
    >>
    >>> E.g.:
    >>>
    >>> class C1(object):
    >>> def __new__(cls, xxx):
    >>> if xxx: return type.__new__(cls, 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__(cls, 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.
     
    Paulo da Silva, Mar 17, 2007
    #10
  11. 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,xxx):
    > if ... :
    > self.foo = foo
    > self.bar = bar
    > else:
    > self=C1.load(xxx)
    >
    > def load(xxx):
    > ...
    > return instance_of_C1
    > load=staticmethod(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(object):
    """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(CachedClass, cls).__new__(cls, ID)
    cls._cache[ID] = obj
    return obj
    def __init__(self, ID):
    print "Calling constructor __init__ ..."
    self.ID = ID



    --
    Steven
     
    Steven D'Aprano, Mar 17, 2007
    #11
  12. Re: Returning other instance from __init__ - I need help

    En Fri, 16 Mar 2007 22:05:05 -0300, Paulo da Silva
    <> escribió:

    > 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(filename)
    inst = super(C, cls).__new__(cls)
    inst.foo = foo
    inst.bar = bar
    return inst

    @classmethod
    def load(cls, filename):
    inst = super(C, cls).__new__(cls)
    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__(cls)
    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
     
    Gabriel Genellina, Mar 17, 2007
    #12
  13. Re: Returning other instance from __init__ - I need help

    Gabriel Genellina escreveu:
    > En Fri, 16 Mar 2007 22:05:05 -0300, Paulo da Silva
    > <> escribió:

    ....

    > class C(object):
    >
    > def __new__(cls, filename=None, foo=None, bar=None):
    > if filename is not None:
    > return cls.load(filename)
    > inst = super(C, cls).__new__(cls)



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

    Thank you very much Gabriel.
    Paulo
     
    Paulo da Silva, Mar 17, 2007
    #13
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Alexander Eberts
    Replies:
    3
    Views:
    325
    Ulrich Petri
    Jul 15, 2003
  2. Steven Bethard
    Replies:
    2
    Views:
    458
    Steven Bethard
    Feb 16, 2005
  3. Kent Johnson
    Replies:
    7
    Views:
    915
    Jan Niklas Fingerle
    Feb 12, 2006
  4. Luis P. Mendes
    Replies:
    3
    Views:
    354
    Bruno Desthuilliers
    Sep 15, 2006
  5. Ramchandra Apte
    Replies:
    17
    Views:
    342
    Manuel Pégourié-Gonnard
    Sep 30, 2012
Loading...

Share This Page