Is there a way to instantiate a class without calling __init__?
Solution 1
You can circumvent __init__
by calling __new__
directly. Then you can create a object of the given type and call an alternative method for __init__
. This is something that pickle
would do.
However, first I'd like to stress very much that it is something that you shouldn't do and whatever you're trying to achieve, there are better ways to do it, some of which have been mentioned in the other answers. In particular, it's a bad idea to skip calling __init__
.
When objects are created, more or less this happens:
a = A.__new__(A, *args, **kwargs)
a.__init__(*args, **kwargs)
You could skip the second step.
Here's why you shouldn't do this: The purpose of __init__
is to initialize the object, fill in all the fields and ensure that the __init__
methods of the parent classes are also called. With pickle
it is an exception because it tries to store all the data associated with the object (including any fields/instance variables that are set for the object), and so anything that was set by __init__
the previous time would be restored by pickle, there's no need to call it again.
If you skip __init__
and use an alternative initializer, you'd have a sort of a code duplication - there would be two places where the instance variables are filled in, and it's easy to miss one of them in one of the initializers or accidentally make the two fill the fields act differently. This gives the possibility of subtle bugs that aren't that trivial to trace (you'd have to know which initializer was called), and the code will be more difficult to maintain. Not to mention that you'd be in an even bigger mess if you're using inheritance - the problems will go up the inheritance chain, because you'd have to use this alternative initializer everywhere up the chain.
Also by doing so you'd be more or less overriding Python's instance creation and making your own. Python already does that for you pretty well, no need to go reinventing it and it will confuse people using your code.
Here's what to best do instead: Use a single __init__
method that is to be called for all possible instantiations of the class that initializes all instance variables properly. For different modes of initialization use either of the two approaches:
- Support different signatures for
__init__
that handle your cases by using optional arguments. - Create several class methods that serve as alternative constructors. Make sure they all create instances of the class in the normal way (i.e. calling
__init__
), as shown by Roman Bodnarchuk, while performing additional work or whatever. It's best if they pass all the data to the class (and__init__
handles it), but if that's impossible or inconvenient, you can set some instance variables after the instance was created and__init__
is done initializing.
If __init__
has an optional step (e.g. like processing that data
argument, although you'd have to be more specific), you can either make it an optional argument or make a normal method that does the processing... or both.
Solution 2
Use classmethod
decorator for your Load
method:
class B(object):
def __init__(self, name, data):
self._Name = name
#store data
@classmethod
def Load(cls, file, newName):
f = open(file, "rb")
s = pickle.load(f)
f.close()
return cls(newName, s)
So you can do:
loaded_obj = B.Load('filename.txt', 'foo')
Edit:
Anyway, if you still want to omit __init__
method, try __new__
:
>>> class A(object):
... def __init__(self):
... print '__init__'
...
>>> A()
__init__
<__main__.A object at 0x800f1f710>
>>> a = A.__new__(A)
>>> a
<__main__.A object at 0x800f1fd50>
Solution 3
Taking your question literally I would use meta classes :
class MetaSkipInit(type):
def __call__(cls):
return cls.__new__(cls)
class B(object):
__metaclass__ = MetaSkipInit
def __init__(self):
print "FAILURE"
def Print(self):
print "YEHAA"
b = B()
b.Print()
This can be useful e.g. for copying constructors without polluting the parameter list. But to do this properly would be more work and care than my proposed hack.
Solution 4
Not really. The purpose of __init__
is to instantiate an object, and by default it really doesn't do anything. If the __init__
method is not doing what you want, and it's not your own code to change, you can choose to switch it out though. For example, taking your class A, we could do the following to avoid calling that __init__
method:
def emptyinit(self):
pass
A.__init__ = emptyinit
a = A()
a.Print()
This will dynamically switch out which __init__
method from the class, replacing it with an empty call. Note that this is probably NOT a good thing to do, as it does not call the super class's __init__
method.
You could also subclass it to create your own class that does everything the same, except overriding the __init__
method to do what you want it to (perhaps nothing).
Perhaps, however, you simply wish to call the method from the class without instantiating an object. If that is the case, you should look into the @classmethod and @staticmethod decorators. They allow for just that type of behavior.
In your code you have put the @staticmethod decorator, which does not take a self
argument. Perhaps what may be better for the purpose would a @classmethod, which might look more like this:
@classmethod
def Load(cls, file, newName):
# Get the data
data = getdata()
# Create an instance of B with the data
return cls.B(newName, data)
UPDATE: Rosh's Excellent answer pointed out that you CAN avoid calling __init__
by implementing __new__
, which I was actually unaware of (although it makes perfect sense). Thanks Rosh!
Solution 5
I was reading the Python cookbook and there's a section talking about this: the example is given using __new__
to bypass __init__()
>>> class A: def __init__(self,a): self.a = a >>> test = A('a') >>> test.a 'a' >>> test_noinit = A.__new__(A) >>> test_noinit.a Traceback (most recent call last): File "", line 1, in test_noinit.a AttributeError: 'A' object has no attribute 'a' >>>
However I think this only works in Python3. Below is running under 2.7
>>> class A: def __init__(self,a): self.a = a >>> test = A.__new__(A) Traceback (most recent call last): File "", line 1, in test = A.__new__(A) AttributeError: class A has no attribute '__new__' >>>
Related videos on Youtube
![Woltan](https://i.stack.imgur.com/iUVL5.png?s=256&g=1)
Woltan
Updated on July 05, 2022Comments
-
Woltan almost 2 years
Is there a way to circumvent the constructor
__init__
of a class in python?Example:
class A(object): def __init__(self): print "FAILURE" def Print(self): print "YEHAA"
Now I would like to create an instance of
A
. It could look like this, however this syntax is not correct.a = A a.Print()
EDIT:
An even more complex example:
Suppose I have an object
C
, which purpose it is to store one single parameter and do some computations with it. The parameter, however, is not passed as such but it is embedded in a huge parameter file. It could look something like this:class C(object): def __init__(self, ParameterFile): self._Parameter = self._ExtractParamterFile(ParameterFile) def _ExtractParamterFile(self, ParameterFile): #does some complex magic to extract the right parameter return the_extracted_parameter
Now I would like to dump and load an instance of that object
C
. However, when I load this object, I only have the single variableself._Parameter
and I cannot call the constructor, because it is expecting the parameter file.@staticmethod def Load(file): f = open(file, "rb") oldObject = pickle.load(f) f.close() #somehow create newObject without calling __init__ newObject._Parameter = oldObject._Parameter return newObject
In other words, it is not possible to create an instance without passing the parameter file. In my "real" case, however, it is not a parameter file but some huge junk of data I certainly not want to carry around in memory or even store it to disc.
And since I want to return an instance of
C
from the methodLoad
I do somehow have to call the constructor.OLD EDIT:
A more complex example, which explains why I am asking the question:
class B(object): def __init__(self, name, data): self._Name = name #do something with data, but do NOT save data in a variable @staticmethod def Load(self, file, newName): f = open(file, "rb") s = pickle.load(f) f.close() newS = B(???) newS._Name = newName return newS
As you can see, since
data
is not stored in a class variable I cannot pass it to__init__
. Of course I could simply store it, but what if the data is a huge object, which I do not want to carry around in memory all the time or even save it to disc?-
Björn Pollex about 13 yearsTo what end do you want to do this?
-
Woltan about 13 yearsI have an "unpickled" object from which I want to create a new object of the same type. However, from this unpickled object I do not have enough data to feed to init. In C++ I would overload the constructor and make it private, in Python I am lost ^^. The current parameters in init however make perfect sense. That is my predicament.
-
pajton about 13 yearsI don't understand why you people vote it down. It is interesting question and given the amount of magic possible in python I believe it is possible with metaclasses or so.
-
pajton about 13 yearsIf this is the case, you should rewrite
__init__
, make its paramters optional or make an additional parameter that allows just basic creation without any initialization -
Dominic Santos about 13 yearsWhat do you mean by circumvent? Do you mean not use it or make it so it doesn't have to be used, or do you mean disable it's use so that it is not callable?
-
Woltan about 13 years@pajton I completely concur! In fact, the question is well stated, boiled down to a minimum of information to understand. Unfortunately people get scared too easily once their minds are forced to go outside their limited comprehensions.
-
Arlaharen about 13 years@Woltan: I still don't understand. Are you doing something like this:
a0 = pickle.load(...); a1 = A(a0)
? -
Woltan about 13 years@Dominic I would like to know, if there is a way to actually create an object without that
__init__
is being called. So more or less the former of your two suggestions ^^. -
DrTyrsa about 13 years1. If you can change the code of class, rewrite it so
__init__
will not require any data. 2. If you can see the code of class, pass some default values. 3. If you can't even see the code of the class, check it's docs, do some experiments, find out it's default values and pass them. Or inherit a new class which doesn't require any data. -
Roman Bodnarchuk about 13 years@Woltan Please, update you question with a problem you want to solve. Do you have a possibility to change class code?
-
Rosh Oxymoron about 13 yearsAny particular reason why you can't simply use the instance returned by
pickle.load
in your new edit?
-
-
Woltan about 13 yearsIn this case in the line
return cls(newName, s)
,data
would bes
. But this is not the case, since I do not know whatdata
is. -
Roman Bodnarchuk about 13 years@Woltan I don't know as well. Maybe you should expand your question once more?
-
Woltan about 13 yearsYeah, I could make parameters default, but this actually does not answer my question. But maybe you are right, and I have a some sort of layout problem in my class.
-
martineau about 13 yearsThe
return cls(newName, s)
is calling__init__()
. -
Woltan about 13 years@martineau That is right, but the second parameter of
__init__
(data
) is of different type thatns
(See my new Edit example) -
kay over 10 yearsOne can even use
a = object.__new__(A)
, if you don't want an overwritenA.__new__
to be called. -
dieterg over 10 yearsThis is a nice solution showing exactly how to override the default
__new__
+__init__
by implementing a custom__call__
method on the metaclass level. It does so without any 'hacking' and allows you to do other useful stuff (like implementing a flyweight pattern) and keep that perfectly hidden from the user. For the user it still looks like a normal constructor call. -
Douglas Bagnall about 9 yearsWith 2.7 you need to use a “new style class” — that is, subclass object:
class A(object)
. -
gbtimmon over 7 yearsValid use for this is if you are building a factory pattern and want to delegate construction to another class but also want to have a default construction in the case that you dont use a factory for the class.
class ThreadPoolFactory : def PersistentThreadPool() : ThreadPool.__new__ .... build and log it