Preferred way of resetting a class in Python
Question:
Based on this post on CodeReview.
I have a class
Foo
in Python (3), which of course includes a __init__()
method. This class fires a couple of prompts and does its thing. Say I want to be able to reset Foo
so I can start the procedure all over again.
What would be the preferred implementation?
Calling the __init__()
method again
def reset(self):
self.__init__()
or creating a new instance?
def reset(self):
Foo()
I am not sure if creating a new instance of Foo
leaves behind anything that might affect performance if reset
is called many times. On the other hand __init__()
might have side-effects if not all attributes are (re)defined in __init__()
.
Is there a preferred way to do this?
Answers:
You could hold the instance you work with in a class attribute.
Whenever you want to reset the class, reassign a new instance to that attribute.
Here is how I would implement this approach:
class Foo:
instance = None # The single instance
def __init__(self, ...):
# Initialize the instance if Foo.instance does not exist, else fail
if type(self).instance is None:
# Initialization
type(self).instance = self
else:
raise RuntimeError("Only one instance of 'Foo' can exist at a time")
@classmethod
def reset(cls):
cls.instance = None # First clear Foo.instance so that __init__ does not fail
cls.instance = Foo(...) # Now the initialization can be called
Then, you can access the instance by simply referring to Foo.instance
.
I chose to have the reset
as a class method, thus decorated by @classmethod
.
With this decorator, the instance can be reset by calling Foo.reset()
, and the cls
parameter will be passed automatically to the method.
I prefer this approach (which is more or less a singleton pattern) over those you suggest, because in your situation, it appears logical to have a single instance of Foo
, since you want to reset it.
Therefore, I find it rather intuitive to “force” the use of a single instance.
On the other hand, you could have an instance outside of the class, and use a reset
instance method, defined:
def reset(self):
self.__init__()
But this might not work so well.
Say you want to set attributes outside of the __init__
method.
Calling __init__
will not reset those attributes.
Therefore, your instance will not be reset as expected.
Now if you hold a single instance and reassign it to a brand new one, you’re certain that it will be absolutely clean.
Regarding what you call “creating a new instance”, that’s more or less what I chose, but the question is where to store it.
I think it makes sense to keep it warm in the class itself.
By the way, there shouldn’t be any performance issue (as in “memory leak”) with this solution, since only one Foo
instance is referenced at a time, and creating a new one will de-reference the previous one.
Both are correct but the semantics are not implemented the same way.
To be able to reset an instance, I would write this (I prefere to call a custom method from __init__
than the opposite, because __init__
is a special method, but this is mainly a matter of taste):
class Foo:
def __init__(self):
self.reset()
def reset(self):
# set all members to their initial value
You use it that way:
Foo foo # create an instance
...
foo.reset() # reset it
Creating a new instance from scratch is in fact simpler because the class has not to implement any special method:
Foo foo # create an instance
...
foo = Foo() # make foo be a brand new Foo
the old instance will be garbage collected if it is not used anywhere else
Both way can be used for normal classes where all initialization is done in __init__
, but the second way is required for special classes that are customized at creation time with __new__
, for example immutable classes.
But beware, this code:
def reset(self):
Foo()
will not do what you want: it will just create a new instance, and immediately delete it because it will go out of scope at the end of the method. Even self = Foo()
would only set the local reference which would the same go out of scope (and the new instance destroyed) at the end of the methos.
As others said, you don’t need to reset a class. But if you really want it, you can use a factory function that returns a new class for every call.
def make_Foo():
class Foo():
VALUE = 1
return Foo
Foo = make_Foo()
Foo.VALUE = 2
print(Foo.VALUE) # prints 2
Foo = make_Foo() # reset
print(Foo.VALUE) # prints 1
I had a similar question myself and had discovered that the best way to do it is:
class MyClass:
def __init__(self):
self.reset()
def reset(self):
self.my_attribute_1 = 0
self.my_attribute_2 = None
self.my_attribute_3 = False
Now you have a reset()
method which you can call on an instance of MyClass
whenever you want to reset all those attributes.
EDIT: However, if you have a dataclass, you need to do it like this:
from dataclasses import dataclass
@dataclass
class MyClass:
def __post_init__(self):
self.reset()
def reset(self):
self.my_attribute_1 = 0
self.my_attribute_2 = None
self.my_attribute_3 = False
Based on this post on CodeReview.
I have a class
Foo
in Python (3), which of course includes a __init__()
method. This class fires a couple of prompts and does its thing. Say I want to be able to reset Foo
so I can start the procedure all over again.
What would be the preferred implementation?
Calling the __init__()
method again
def reset(self):
self.__init__()
or creating a new instance?
def reset(self):
Foo()
I am not sure if creating a new instance of Foo
leaves behind anything that might affect performance if reset
is called many times. On the other hand __init__()
might have side-effects if not all attributes are (re)defined in __init__()
.
Is there a preferred way to do this?
You could hold the instance you work with in a class attribute.
Whenever you want to reset the class, reassign a new instance to that attribute.
Here is how I would implement this approach:
class Foo:
instance = None # The single instance
def __init__(self, ...):
# Initialize the instance if Foo.instance does not exist, else fail
if type(self).instance is None:
# Initialization
type(self).instance = self
else:
raise RuntimeError("Only one instance of 'Foo' can exist at a time")
@classmethod
def reset(cls):
cls.instance = None # First clear Foo.instance so that __init__ does not fail
cls.instance = Foo(...) # Now the initialization can be called
Then, you can access the instance by simply referring to Foo.instance
.
I chose to have the reset
as a class method, thus decorated by @classmethod
.
With this decorator, the instance can be reset by calling Foo.reset()
, and the cls
parameter will be passed automatically to the method.
I prefer this approach (which is more or less a singleton pattern) over those you suggest, because in your situation, it appears logical to have a single instance of Foo
, since you want to reset it.
Therefore, I find it rather intuitive to “force” the use of a single instance.
On the other hand, you could have an instance outside of the class, and use a reset
instance method, defined:
def reset(self):
self.__init__()
But this might not work so well.
Say you want to set attributes outside of the __init__
method.
Calling __init__
will not reset those attributes.
Therefore, your instance will not be reset as expected.
Now if you hold a single instance and reassign it to a brand new one, you’re certain that it will be absolutely clean.
Regarding what you call “creating a new instance”, that’s more or less what I chose, but the question is where to store it.
I think it makes sense to keep it warm in the class itself.
By the way, there shouldn’t be any performance issue (as in “memory leak”) with this solution, since only one Foo
instance is referenced at a time, and creating a new one will de-reference the previous one.
Both are correct but the semantics are not implemented the same way.
To be able to reset an instance, I would write this (I prefere to call a custom method from __init__
than the opposite, because __init__
is a special method, but this is mainly a matter of taste):
class Foo:
def __init__(self):
self.reset()
def reset(self):
# set all members to their initial value
You use it that way:
Foo foo # create an instance
...
foo.reset() # reset it
Creating a new instance from scratch is in fact simpler because the class has not to implement any special method:
Foo foo # create an instance
...
foo = Foo() # make foo be a brand new Foo
the old instance will be garbage collected if it is not used anywhere else
Both way can be used for normal classes where all initialization is done in __init__
, but the second way is required for special classes that are customized at creation time with __new__
, for example immutable classes.
But beware, this code:
def reset(self):
Foo()
will not do what you want: it will just create a new instance, and immediately delete it because it will go out of scope at the end of the method. Even self = Foo()
would only set the local reference which would the same go out of scope (and the new instance destroyed) at the end of the methos.
As others said, you don’t need to reset a class. But if you really want it, you can use a factory function that returns a new class for every call.
def make_Foo():
class Foo():
VALUE = 1
return Foo
Foo = make_Foo()
Foo.VALUE = 2
print(Foo.VALUE) # prints 2
Foo = make_Foo() # reset
print(Foo.VALUE) # prints 1
I had a similar question myself and had discovered that the best way to do it is:
class MyClass:
def __init__(self):
self.reset()
def reset(self):
self.my_attribute_1 = 0
self.my_attribute_2 = None
self.my_attribute_3 = False
Now you have a reset()
method which you can call on an instance of MyClass
whenever you want to reset all those attributes.
EDIT: However, if you have a dataclass, you need to do it like this:
from dataclasses import dataclass
@dataclass
class MyClass:
def __post_init__(self):
self.reset()
def reset(self):
self.my_attribute_1 = 0
self.my_attribute_2 = None
self.my_attribute_3 = False