Can __new__ prevent __init__ from being called?

Steven Bethard steven.bethard at gmail.com
Tue Feb 15 17:01:10 EST 2005


Felix Wiemann wrote:
> Sometimes (but not always) the __new__ method of one of my classes
> returns an *existing* instance of the class.  However, when it does
> that, the __init__ method of the existing instance is called
> nonetheless, so that the instance is initialized a second time.
>
[snip]
> 
> How can I prevent __init__ from being called on the already-initialized
> object?

The short answer: you can't:
     http://www.python.org/2.2.3/descrintro.html#__new__
Note that in the Singleton example there, subclasses are told to 
override init, not __init__ for exactly this reason.

If it's okay that __init__ never be called, you could do something like:

py> class C(object):
...     class __metaclass__(type):
...         def __call__(cls, *args, **kwargs):
...             return cls.__new__(cls, *args, **kwargs)
...     instance = None
...     def __new__(cls):
...         if cls.instance is None:
...             print 'Creating instance'
...             cls.instance = object.__new__(cls)
...             print 'Created'
...         return cls.instance
...     def __init__(self):
...         print 'In init'
...
py> C()
Creating instance
Created
<__main__.C object at 0x011F2E30>
py> C()
<__main__.C object at 0x011F2E30>

If __init__ needs to be called, I might go with something like:

py> class C(object):
...     class __metaclass__(type):
...         def __call__(cls, *args, **kwargs):
...             if cls.instance is None:
...                 print 'Creating instance'
...                 cls.instance = cls.__new__(cls, *args, **kwargs)
...                 print 'Created'
...                 cls.instance.__init__(*args, **kwargs)
...             return cls.instance
...     instance = None
...     def __init__(self):
...         print 'In init'
...
py> C()
Creating instance
Created
In init
<__main__.C object at 0x011F2E50>
py> C()
<__main__.C object at 0x011F2E50>

where all the work is done in the metaclass and you don't even define 
__new__.  I would probably also create the 'instance' attribute as part 
of the metaclass work, like:

py> class SingletonMetaclass(type):
...     def __call__(cls, *args, **kwargs):
...         try:
...             return cls.__instance__
...         except AttributeError:
...             cls.__instance__ = cls.__new__(cls, *args, **kwargs)
...             cls.__instance__.__init__(*args, **kwargs)
...             return cls.__instance__
...
py> class C(object):
...     __metaclass__ = SingletonMetaclass
...     def __init__(self):
...         print '__init__'
...
py> C()
__init__
<__main__.C object at 0x011F3210>
py> C()
<__main__.C object at 0x011F3210>
py> C() is C()
True

But none of these solutions is particularly simple...  Sorry!

STeVe



More information about the Python-list mailing list