Create new class instance from class method
Solution 1
class Organism(object):
def reproduce(self):
#use self here to customize the new organism ...
return Organism()
Another option -- if the instance (self
) isn't used within the method:
class Organism(object):
@classmethod
def reproduce(cls):
return cls()
This makes sure that Organisms produce more Organisms and (hypothetical Borgs which are derived from Organisms produce more Borgs).
A side benefit of not needing to use self
is that this can now be called from the class directly in addition to being able to be called from an instance:
new_organism0 = Organism.reproduce() # Creates a new organism
new_organism1 = new_organism0.reproduce() # Also creates a new organism
Finally, if both the instance (self
) and the class (Organism
or subclasses if called from a subclass) are used within the method:
class Organism(object):
def reproduce(self):
#use self here to customize the new organism ...
return self.__class__() # same as cls = type(self); return cls()
In each case, you'd use it as:
organism = Organism()
new_organism = organism.reproduce()
Solution 2
why not simply use the copy module?
import copy
organism = Organism()
replica = copy.deepcopy(organism)
Solution 3
What about something like this:
class Organism(object):
population = []
def __init__(self, name):
self.name = name
self.population.append(self)
def have_one_child(self, name):
return Organism(name)
def reproduce(self, names):
return [self.have_one_child(name) for name in names]
Result:
>>> a = Organism('a')
>>> len(Organism.population)
1
>>> a.reproduce(['x', 'y', 'z']) # when one organism reproduces, children are added
# to the total population
# organism produces as many children as you state
[<__main__.Organism object at 0x05F23190>, <__main__.Organism object at 0x05F230F0>, <__main__.Organism object at 0x05F23230>]
>>> for ele in Organism.population:
... print ele.name
...
a
x
y
z
>>> Organism.population[3].reproduce(['f', 'g'])
[<__main__.Organism object at 0x05F231D0>, <__main__.Organism object at 0x05F23290>]
>>> for ele in Organism.population:
... print ele.name
...
a
x
y
z
f
g
Solution 4
I believe you are asking how to copy an object. Surprisingly (maybe), there is (almost) no standard method for this, and this is by design. The issue comes from the intrinsic ambiguity of the idea of copying, i.e.: when you copy an object property do you mean to copy it as reference (copy) or as value (deepcopy)?
However, in the majority of cases you want a consistent behavior (deepcopy or copy for all properties), in this case you can use copy
module as
import copy
new_obj = copy.copy(old_obj)
or
new_obj = copy.deepcopy(old_obj)
In a generic case in which you want a more customized behavior, you use the same commands, but override the __copy__
and __deepcopy__
methods of your objects.
See more answers for details and examples, e.g.: How to override the copy/deepcopy operations for a Python object?
Solution 5
The same way you did originally, but then you have to do something with it!
organism = Organism()
calls the class Organism
(parentheses directly after a name is the "call" operation). This creates and returns a new instance of the class, which you then bind to the name organism
.
When you execute that line in the interpreter, you now have a variable organism
referring to the new Organism
instance you just created.
When you write that line inside a function (including a method, because there's no difference between a method and a function "from the inside"), it does the same thing, but the variable organism
is a local variable. Local variables are thrown away when the function is finished, so this does create a new Organism
instance, but it doesn't achieve anything because you never gain access to it.
Your function should return any information it wants to communicate to its caller. Any local variables that you don't return are only useful if you use those variables to create something you do return.
Note that this has nothing to do with your particular problem of creating an instance inside a method; it's just how functions/methods work in general. You will need to learn how functions work before you can successfully write object-oriented programs using classes and instances; I would strongly suggest you work through some tutorials.
ohblahitsme
Updated on July 09, 2022Comments
-
ohblahitsme almost 2 years
I want to be able to create a new instance of an object by calling a method on an already instantiated object. For example, I have the object:
organism = Organism()
I want to be able to call
organism.reproduce()
and have two objects of type Organism. My method at this point looks like this:class Organism(object): def reproduce(): organism = Organism()
and I'm pretty sure it doesn't work (I'm not really even sure how to test it. I tried the gc method in this post). So how can I make my object create a copy of itself that's accessible just like the first object I created (with
organism = Organism()
)? -
isosceleswheel about 7 yearsI found this explanation quite helpful, but can you elaborate on what you meant by "if the instance doesn't matter" vs. "if both the instance and the class matter"? Both the
@classmethod
approach and theself.__class__()
approach work in my case: I have a base class methodget_copy
that creates a new instance (?) of the subclass and then I use the__dict__
to turn the new subclass into a "copy" of the original. Is one approach more appropriate than the other in this case? -
mgilson about 7 years@isosceleswheel -- I've updated the text slightly. Basically I was talking about what data the function needs to create a new instance. In other words, "If the instance doesn't matter" was the same thing as saying "If
self
isn't used in the function". Hopefully the updated text makes it more clear. -
TheGrimmScientist almost 3 yearsgood answer, but attached to the wrong question.
-
Vincenzooo almost 3 yearsThanks! but why do you say that? I understand this is what is asked when it says "So how can I make my object create a copy of itself that's accessible just like the first object.." (also from first comment to question, I am not the only one who understands the same.
-
TheGrimmScientist almost 3 yearsDoes you solution show how your copy is made "by calling a method on an already instantiated object"? No. You're making the copy yourself, not by defining then calling a function on / within
old_obj
. -
Vincenzooo over 2 yearsFor a generic copy, you might write a method (e.g.
old_obj.replicate()
) that returnscopy.copy(self)
, but there is little reason for using such a method: you can just callcopy.copy(old_obj)
. I think this is the standard way to make a copy, since it works even with more object-specific methods (e.g. copy some properties and reference others) which override the__copy__
method of the object.