473,408 Members | 1,788 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,408 software developers and data experts.

Can __new__ prevent __init__ from being called?

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. For
example, please consider the following class (a singleton in this case):
class C(object): .... instance = None
.... def __new__(cls):
.... if C.instance is None:
.... print 'Creating instance.'
.... C.instance = object.__new__(cls)
.... print 'Created.'
.... return cls.instance
.... def __init__(self):
.... print 'In init.'
.... C() Creating instance.
Created.
In init.
<__main__.C object at 0x4062526c> C() In init. <---------- Here I want __init__ not to be executed.
<__main__.C object at 0x4062526c>


How can I prevent __init__ from being called on the already-initialized
object?

I do not want to have any code in the __init__ method which checks if
the instance is already initialized (like "if self.initialized: return"
at the beginning) because that would mean I'd have to insert this
checking code in the __init__ method of every subclass.

Is there an easier way than using a metaclass and writing a custom
__call__ method?

--
Felix Wiemann -- http://www.ososo.de/
Jul 18 '05 #1
9 6156
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
Jul 18 '05 #2
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. For
example, please consider the following class (a singleton in this case):
[snip] How can I prevent __init__ from being called on the already-initialized
object?


Is this an acceptable kludge?
class C(object): .... instance=None
.... def __new__(cls):
.... if C.instance is None:
.... print 'creating'
.... C.instance = object.__new__(cls)
.... else:
.... cls.__init__ = lambda self: None
.... return cls.instance
.... def __init__(self):
.... print 'in init'
.... a = C() creating
in init b = C()


(Translation: dynamically override now-useless __init__ method.
But if that works, why do you need __init__ in the first place?)

-Peter
Jul 18 '05 #3
Peter Hansen wrote:
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. For
example, please consider the following class (a singleton in this case):

[snip]
How can I prevent __init__ from being called on the already-initialized
object?

Is this an acceptable kludge?
>>> class C(object): ... instance=None
... def __new__(cls):
... if C.instance is None:
... print 'creating'
... C.instance = object.__new__(cls)
... else:
... cls.__init__ = lambda self: None
... return cls.instance
... def __init__(self):
... print 'in init'
... >>> a = C() creating
in init >>> b = C()
>>>
(Translation: dynamically override now-useless __init__ method.
But if that works, why do you need __init__ in the first place?)

-Peter

Or this one: use an alternative constructor:

class C(object):
instance = None
@classmethod
def new(cls, *args, **kw):
if cls.instance is None:
print 'Creating instance.'
cls.instance = object.__new__(cls)
print 'Created.'
cls.instance.__init__(*args,**kw)
return cls.instance
def __init__(self):
print 'In init.'
c = C.new() Creating instance.
Created.
In init. c = C.new()


Michael

Jul 18 '05 #4
Steven Bethard wrote:
Felix Wiemann wrote:
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__


What a pity. By the way, I'm just seeing that the web page says:

| If you return an existing object, the constructor call will still call
| its __init__ method. If you return an object of a different class, its
| __init__ method will be called.

However, the latter doesn't seem to be true, or am I missing something?
class A(object): .... def __init__(self):
.... print 'Init of A.'
.... instance = A() Init of A. class B(object): .... def __new__(self):
.... return instance
.... def __init__(self):
.... print 'Init of B.'
.... B() # <--------- A's __init__ is *not* called. <__main__.A object at 0x4062424c> instance = object.__new__(B)
B() # <--------- B's __init__ is called

Init of B.
<__main__.B object at 0x406243ec>

So there seems to be some type-checking in type.__call__.
Note that in the Singleton example there, subclasses are told to
override init, not __init__ for exactly this reason.
I see.
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
I didn't think of inlining the metaclass; that's really nice.
[...] where all the work is done in the metaclass and you don't even
define __new__.


Yeah, that's good. I think I'll go that way.

Thanks a lot!

--
Felix Wiemann -- http://www.ososo.de/
Jul 18 '05 #5
On Tue, Feb 15, 2005 at 10:30:21PM +0100, 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. For
example, please consider the following class (a singleton in this case):
class C(object):
... instance = None
... def __new__(cls):
... if C.instance is None:
... print 'Creating instance.'
... C.instance = object.__new__(cls)
... print 'Created.'
... return cls.instance
... def __init__(self):
... print 'In init.'
...

<snip> How can I prevent __init__ from being called on the already-initialized
object? <snip> Is there an easier way than using a metaclass and writing a custom
__call__ method?


The standard recipe is to define an alternate init method and call it
once when you instantiate the object (I couldn't find it on ASPN though).

Here is a cut-n-paste from production code. The work normally done in
the magic __init__() is done in init() instead.

class Page(context.AppContext):
"""the One True Singleton """
_single = None # our singleton reference
def __new__(cls, *args, **opts):
if (Page._single is None):
Page._single = object.__new__(cls)
Page._single.init(*args, **opts)
return Page._single

def __init__(self, *args, **opts):
"""We are a singleton, so setup is done just once in init() because
__init__() will be called every time the singleton is re-issued
This __init__ just prevents our parent's __init__'s from running other
than when told to by our init()
"""
return

def init(self, req = None):
"""setup Db objects, cgi params etc
Here is also where we decide if we are being run from the command
line or in mod_python"""
context.AppContext.__init__(self, req)
# lots of initialization done here
return

Page is a singleton but it inherits from the class context.AppContext
which is just a regular class. The empty Page.__init__ doesn't call
the context.AppContext.__init__ but the once-only Page.init does.

Hope that helps,

-Jack
Jul 18 '05 #6
Felix Wiemann wrote:
Steven Bethard wrote:

Felix Wiemann wrote:

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__

[snip]
This prompts a similar query. __new__ appears to be intended for
immutable objects but it seems to be called as part of constructor
process for all instances.

Regarding the original question. It is not possible to prevent the use
of __init__ but is it possible to prevent __init__ having any effect by
setting a flag when __init__ is called for the first creation of the
instance.

Colin W.

Jul 18 '05 #7
Colin J. Williams wrote:
This prompts a similar query. __new__ appears to be intended for
immutable objects but it seems to be called as part of constructor
process for all instances.


That's because Python has no builtin way of determining whether or not a
given type is immutable. If you wanted to, you could define both
__new__ and __init__, the first to set immutable parts and the second to
set mutable parts, e.g.:

py> class PartlyMutableTuple(tuple):
.... def __new__(cls, *args, **kwargs):
.... return super(PartlyMutableTuple, cls).__new__(cls, args)
.... def __init__(self, *args, **kwargs):
.... self.__dict__.update(kwargs)
....
py> t = PartlyMutableTuple(1, 2, 3, a=4, b=5)
py> t
(1, 2, 3)
py> t.a, t.b
(4, 5)
py> t.a, t.b = t.b, t.a
py> t.a, t.b
(5, 4)
py> t[0] = 2
Traceback (most recent call last):
File "<interactive input>", line 1, in ?
TypeError: object does not support item assignment

I don't think I'd advise this strategy, but by always calling both
__new__ and __init__, Python makes it possible...

Steve
Jul 18 '05 #8
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?

I do not want to have any code in the __init__ method which checks if
the instance is already initialized (like "if self.initialized: return" at the beginning) because that would mean I'd have to insert this
checking code in the __init__ method of every subclass.

Is there an easier way than using a metaclass and writing a custom
__call__ method?


Yes. You could move all your initalization logic from __init__ to a
separate init method and use the following simple recipe that does not
involve metaclasses and overriding __call__.

Although the base class __init__ does have to check to see if the
instance is initialized, you don't have to repeat the code in derived
classes:

class C(object):
def __new__(cls, *args, **kwds):
it = cls.__dict__.get("__it__")
if it is not None:
return it
cls.__it__ = it = object.__new__(cls)
it.init(*args, **kwds)
return it

def init(self, *args, **kwds): # only called once
print 'In C init.'
pass

def __init__(self): # called each time
print 'In C __init__.'

class D(C):
def init(self, *args, **kwds): # only called once
print 'In D init.'
pass

def __init__(self): # called each time
print 'In D __init__.'
C() In C init.
In C __init__.
C() In C __init__.
D() In D init.
In D __init__.
D()

In D __init__.

-Martin

Jul 18 '05 #9
I meant to say:

Although the base class __new__ does have to check to see if the
^^^^^^^
instance is initialized, ...

not:
Although the base class __init__ does have to check to see if the
instance is initialized, ...


Jul 18 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: Uwe Mayer | last post by:
Hi, I want to create a copy of an object from out of its base class: class A(object): def copy(self): .... class B(A): ....
3
by: Christoph Groth | last post by:
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1.0.6 (GNU/Linux) Comment: For info see http://www.gnupg.org iD8DBQBAJmKufx2/njzvX5URAipnAKCUco5ZCl85xJ8YboHHJM3RBIqiGwCfX3/P...
2
by: Steven Bethard | last post by:
Felix Wiemann wrote: > Steven Bethard wrote: >> http://www.python.org/2.2.3/descrintro.html#__new__ > > > I'm just seeing that the web page says: > > | If you return an existing object,...
3
by: James Stroud | last post by:
Hello All, I'm running 2.3.4 I was reading the documentation for classes & types http://www.python.org/2.2.3/descrintro.html And stumbled on this paragraph: """ __new__ must return an...
5
by: Ken Schutte | last post by:
Hi, I'm been trying to create some custom classes derived from some of python's built-in types, like int and list, etc. I've run into some trouble, which I could explain with a couple simple...
1
by: Frank Benkstein | last post by:
Hi, the behaviour I always observed when creating instances by calling the class A is that '__init__' is always only called when the object returned by A.__new__ is an instance of A. This can be...
5
by: Sandra-24 | last post by:
Ok here's the problem, I'm modifying a 3rd party library (boto) to have more specific exceptions. I want to change S3ResponseError into about 30 more specific errors. Preferably I want to do this...
4
by: Steven D'Aprano | last post by:
When you call a new-style class, the __new__ method is called with the user-supplied arguments, followed by the __init__ method with the same arguments. I would like to modify the arguments...
3
by: Torsten Mohr | last post by:
Hi, i have some questions related to new style classes, they look quite useful but i wonder if somebody can give me an example on constructors using __new__ and on using __init__ ? I just see...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.