Create new class instance from class method

Question:

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())?

Asked By: ohblahitsme

||

Answers:

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()
Answered By: mgilson

why not simply use the copy module?

import copy
organism = Organism()
replica = copy.deepcopy(organism)
Answered By: jcr
from copy import copy                                                           

class Organism(object):                                                         

    def __init__(self,name):                                                    
        self.name=name                                                          

    def setName(self,name):                                                     
        self.name=name                                                          

    def reproduce(self,childname):     
        #use deepcopy if necessary                                         
        cp = copy(self)                                                         
        cp.setName("descendant from " + self.name + " " + childname)            
        return cp                                                               

    def __str__(self):                                                          
        return self.name                                                        

first = Organism("first")                                                       
second = first.reproduce("second")                                              

print first                                                                     
print second 
Answered By: RParadox

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.

Answered By: Ben

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
Answered By: Akavall

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?

Answered By: Vincenzooo
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.