How can I create a copy of an object in Python?
To get a fully independent copy of an object you can use the copy.deepcopy()
function.
For more details about shallow and deep copying please refer to the other answers to this question and the nice explanation in this answer to a related question.
Make copy of object instance in Python
If you want to make a copy then one way is using deepcopy
:
from copy import deepcopy
B = deepcopy(A)
All =
does is to assign another reference to the same object in memory. The deepcopy
creates a whole new object in memory with the values of A
and B
will reference it. if you do the following you will see different prints:
B = A
print( id(A), id(B)) # Same ids
B = deepcopy(A)
print( id(A), id(B) # Different ids
Cloning an object in Python
The line self = sample
only overwrites a local variable, it does not replace the object initially stored in self
.
To copy instances of a class, you have to fully define how to build a new object from an existing one.
You do this by defining the __copy__
and __deepcopy__
methods. These are the dunder methods used by copy.copy
and copy.deepcopy
respectively.
Although, note that it is bad practice to have input
in your __init__
as it impedes the above solution. You should separate your logic and your IO.
import copy
class test():
def __init__(self, a, b):
self.a, self.b = a, b
def __copy__(self):
return type(self)(self.a, self.b)
# Here we encapsulate the IO part of your code
def test_factory():
a = int(input())
b = int(input())
return test(a, b)
foo = test_factory()
... # input the attributes
bar = copy.copy(foo) # a copy of your object
How to copy a Python class instance if deepcopy() does not work?
I have mostly figured it out. The only problem which I cannot overcome is knowing an acceptable set of initialization arguments (arguments for __init__
) for all classes. So I have to make the following two assumtions:
1) I have a set of default arguments for class C
which I call argsC
.
2) All objects in C
can be initialized with empty arguments.
In which case I can
First:
Initialize a new instance of the class C
from it's instance which I want to copy c
:
c_copy = c.__class__(**argsC)
Second:
Go through all the attributes of c
and set the attributes c_copy
to be a copy of the attributes of c
for att in c.__dict__:
setattr(c_copy, att, object_copy(getattr(c,att)))
where object_copy
is a recursive application of the function we are building.
Last:
Delete all attributes in c_copy
but not in c
:
for att in c_copy.__dict__:
if not hasattr(c, att):
delattr(c_copy, att)
Putting this all together we have:
import copy
def object_copy(instance, init_args=None):
if init_args:
new_obj = instance.__class__(**init_args)
else:
new_obj = instance.__class__()
if hasattr(instance, '__dict__'):
for k in instance.__dict__ :
try:
attr_copy = copy.deepcopy(getattr(instance, k))
except Exception as e:
attr_copy = object_copy(getattr(instance, k))
setattr(new_obj, k, attr_copy)
new_attrs = list(new_obj.__dict__.keys())
for k in new_attrs:
if not hasattr(instance, k):
delattr(new_obj, k)
return new_obj
else:
return instance
So putting it all together we have:
argsC = {'a':1, 'b':1}
c = C(4,5,r=[[1],2,3])
c.a = 11
del c.b
c_copy = object_copy(c, argsC)
c.__dict__
{'a': 11, 'r': [[1], 2, 3]}
c_copy.__dict__
{'a': 11, 'r': [[1], 2, 3]}
c.__dict__
{'a': 11, 'r': [[1, 33], 2, 3]}
c_copy.__dict__
{'a': 11, 'r': [[1], 2, 3]}
Which is the desired outcome. It uses deepcopy
if it can, but for the cases where it would raise an exception, it can do without.
How to copy instances of a custom defined class in Python 3.3?
In general, you can use the copy
module to produce copies of Python objects.
copy.copy()
will produce a shallow copy; a new instance is created but all attributes are simply copied over. If any of your attributes are mutable and you mutate those objects you'll see those changes reflected on both objects.copy.deepcopy()
will produce a copy recursively; any mutable objects will themselves be cloned.
If your class implements a __copy__
method it'll be used to create a shallow copy of the object; return a new instance with attributes copied over and altered as needed.
Similarly, you can implement a __deepcopy__
method to implement a custom deep copy method; it'll be passed the memo
state, pass this on to recursive copy.deepcopy()
calls.
Note that you cannot use this to copy a class object however. Classes are meant to be singletons; you don't need to create a copy in that case. You can use subclassing instead, or a class factory function, to produce distinct class objects.
how to make a copy of a class in python?
The problem you're encountering is that looking up a method attribute on a Python 2 class creates an unbound method, it doesn't return the underlying raw function (on Python 3, unbound methods are abolished, and what you're attempting would work just fine). You need to bypass the descriptor protocol machinery that converts from function to unbound method. The easiest way is to use vars
to grab the class's attribute dictionary directly:
# Make copy of A's attributes
Bvars = vars(A).copy()
# Modify the desired attribute
Bvars['a'] = 2
# Construct the new class from it
B = type('B', (object,), Bvars)
Equivalently, you could copy and initialize B
in one step, then reassign B.a
after:
# Still need to copy; can't initialize from the proxy type vars(SOMECLASS)
# returns to protect the class internals
B = type('B', (object,), vars(A).copy())
B.a = 2
Or for slightly non-idiomatic one-liner fun:
B = type('B', (object,), dict(vars(A), a=2))
Either way, when you're done:
B().foo()
will output:
2
10
as expected.
How to create copies of a python object that are not linked to original object?
The simplest way to make a shallow copy of a dictionary is to use the dict's copy
method:
In [1]: template = {'thing1': '', 'thing2': '', 'thing3': ''}
In [2]: apile = template.copy()
In [3]: apile['thing1'] = 1
In [4]: apile
Out[4]: {'thing1': 1, 'thing2': '', 'thing3': ''}
In [5]: template
Out[5]: {'thing1': '', 'thing2': '', 'thing3': ''}
To make a shallow copy of a list, you can take a slice of the entire list:
copied_list = original_list[:]
If you need to clone other things, or if you need a deep copy of a dict of dicts (or a list of dicts, or other mutable objects), you should use the copy
module: http://docs.python.org/2/library/copy.html
copy.copy(x)
Return a shallow copy of x.
copy.deepcopy(x)
Return a deep copy of x.
The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists or class instances):
- A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original.
- A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.
About your second way: sure, you can create a dict out of another dict, and it will be a copy:
In [23]: p = dict(template)
In [24]: p['thing1'] = 1
In [25]: template
Out[25]: {'thing1': '', 'thing2': '', 'thing3': ''}
In [26]: p
Out[26]: {'thing1': 1, 'thing2': '', 'thing3': ''}
How to make deep copy of a specific(mutable) object?
Generally, Python has a library named 'copy' which implements deepcopy of the basic objects. Try to use from copy import deepcopy
and override the __eq__
function of Board.
For more information, take a look at How can I create a copy of an object in Python?
Related Topics
How to Open a File Using the Open with Statement
How to Time a Code Segment for Testing Performance with Pythons Timeit
Convert Pandas Timezone-Aware Datetimeindex to Naive Timestamp, But in Certain Timezone
Display a Decimal in Scientific Notation
Changing User Agent on Urllib2.Urlopen
Differencebetween an Expression and a Statement in Python
How to Jump to a Particular Line in a Huge Text File
Plot a Horizontal Line on a Given Plot
Elegant Python Code for Integer Partitioning
How to Un-Escape a Backslash-Escaped String
Python Pandas Remove Duplicate Columns
How to Get Week Number in Python
How to Access Command Line Arguments
Does "\D" in Regex Mean a Digit
Determining Application Path in a Python Exe Generated by Pyinstaller