Returning other instance from __init__

P

Paulo da Silva

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
 
A

Alex Martelli

Paulo da Silva said:
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
 
D

Dennis Lee Bieber

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
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 
P

Paul Boddie

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
 
A

Alex Martelli

Paul Boddie said:
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
 
P

Paulo da Silva

Alex Martelli escreveu:
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
 
P

Paul Boddie

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.
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
 
A

Alex Martelli

Paulo da Silva said:
Alex Martelli escreveu:


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
 
P

Paulo da Silva

Paulo da Silva escreveu:
Alex Martelli escreveu:


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.
 
P

Paulo da Silva

Paulo da Silva escreveu:
Paulo da Silva escreveu:
This does not work(!) at least for python 2.4.3.


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.
 
S

Steven D'Aprano

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
 
G

Gabriel Genellina

En Fri, 16 Mar 2007 22:05:05 -0300, Paulo da Silva
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
 
P

Paulo da Silva

Gabriel Genellina escreveu:
En Fri, 16 Mar 2007 22:05:05 -0300, Paulo da Silva
<[email protected]> 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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top