cause __init__ to return a different class?

M

Matthew Pounsett

I'm wondering if there's a way in python to cause __init__ to return a class other than the one initially specified. My use case is that I'd like to have a superclass that's capable of generating an instance of a random subclass.

I've tried both returning the subclass (as I would when overloading an operator) but I get the complaint that __init__ wants to return None instead of a type.

The other thing I tried was overwriting 'self' while inside __init__ but that doesn't seem to work either.

class Parent(object):
def __init__(self, foo):
if foo == True:
self = Child(foo)

class Child(Parent):
def __init__(self, foo):
pass

Is there a way to do this?
 
R

Ryan Kelly



The above will do exactly what you want, but it's generally bad style
unless you have a very specific use-case. Is there a particular reason
you need to "magically" return a subclass, rather than making this
explicit in the code?

To be friendlier to others reading your code, I would consider using a
classmethod to create an alternative constructor:


class MyBaseClass(object):

@classmethod
def get_random_subclass(cls, *args, **kwds)
subcls = random.choice(cls.__subclasses__())
return subcls(*args, **kwds)


To me, this reads pretty cleanly and makes it obvious that something
unusual is going on:

obj = MyBaseClass.get_random_subclass()

While this hides the intention of the code and would require additional
documentation or comments:

obj = MyBaseClass() # note: actually returns a subclass!



Just a thought :)


Cheers,

Ryan


--
Ryan Kelly
http://www.rfk.id.au | This message is digitally signed. Please visit
(e-mail address removed) | http://www.rfk.id.au/ramblings/gpg/ for details




-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk5xkv4ACgkQfI5S64uP50qOMwCfTE9QoHL0Ab2QrMqsDu3iKiCa
TBAAoI9zgv3FIMyTzyKbwXOVe/sx+0/v
=xevq
-----END PGP SIGNATURE-----
 
S

Steven D'Aprano

I'm wondering if there's a way in python to cause __init__ to return a
class other than the one initially specified. My use case is that I'd
like to have a superclass that's capable of generating an instance of a
random subclass.


You need to override the constructor, not the initializer. By the time
__init__ is called, the instance has already been created.

I've tried both returning the subclass (as I would when overloading an
operator) but I get the complaint that __init__ wants to return None
instead of a type.

The other thing I tried was overwriting 'self' while inside __init__ but
that doesn't seem to work either.

No, because self is just an ordinary local variable. Overwriting self just
changes the local variable, not the instance.

However, you can sometimes modify the instance's class. One sometimes useful
trick is something like this:


class Test(object):
def __init__(self):
if condition():
self.__class__ = AnotherClass

which will work, and is supported, so long as Test class and AnotherClass
are compatible. (If they're not compatible, you'll get an exception.)
 
J

Jonathan Hartley

Perhaps a more idiomatic way of achieving the same thing is to use a factory function, which returns instances of different classes:

def PersonFactory(foo):
if foo:
return Person()
else:
return Child()


Apologies if the code is messed up, I'm posting from Google groups web UI.
 
M

Matthew Pounsett

The above will do exactly what you want, but it's generally bad style
unless you have a very specific use-case.  Is there a particular reason
you need to "magically" return a subclass, rather than making this
explicit in the code?

To be friendlier to others reading your code, I would consider using a
classmethod to create an alternative constructor:

Yeah, I was considering doing this as well, particularly if I couldn't
have made the other work. The reason I'm not too concerned about
anyone misinterpreting what's going on is that in this case the base
class is actually named for being a constructor, and any rare case
where I want a specific subclass the subclass will be created
directly.

Thanks very much for your help!
 
A

Arnaud Delobelle

Aha.. thanks!  The reference book I'm working from neglects to mention
__new__, so I'd assumed __init__ was the constructor.  It hadn't
occurred to me that python would separate the functions (I still don't
see exactly why it would be useful to do that, but perhaps insight
will come with time).

If you're interested in the reason, I suggest you read Guido's essay
on "new style classes" which were introduced in Python 2.2 (and are
now a good 10 years old I think):

http://www.python.org/download/releases/2.2.3/descrintro
 
M

Matthew Pounsett

To be friendlier to others reading your code, I would consider using a
classmethod to create an alternative constructor:

I finally got back to looking at this today. As it turns out, un-
overriding __new__ in the child class is more complicated than I first
expected, and isn't worth the extra effort. So, I ended up using a
constructor class method as you suggested.

Thanks again!
 

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

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,072
Latest member
trafficcone

Latest Threads

Top