जवाबों:
किसी ऑब्जेक्ट की पूरी तरह से स्वतंत्र प्रतिलिपि प्राप्त करने के लिए आप copy.deepcopy()
फ़ंक्शन का उपयोग कर सकते हैं ।
उथले और गहरी नकल के बारे में अधिक जानकारी के लिए कृपया इस प्रश्न के अन्य उत्तरों और संबंधित प्रश्न के इस उत्तर में अच्छी व्याख्या देखें ।
मैं पायथन में किसी ऑब्जेक्ट की कॉपी कैसे बना सकता हूं?
इसलिए, यदि मैं नई वस्तु के क्षेत्रों के मूल्यों को बदलता हूं, तो पुरानी वस्तु उससे प्रभावित नहीं होनी चाहिए।
तुम तो एक उत्परिवर्तनीय वस्तु का मतलब है।
पायथन 3 में, सूचियों को एक copy
विधि मिलती है (2 में, आप प्रतिलिपि बनाने के लिए एक स्लाइस का उपयोग करेंगे):
>>> a_list = list('abc')
>>> a_copy_of_a_list = a_list.copy()
>>> a_copy_of_a_list is a_list
False
>>> a_copy_of_a_list == a_list
True
उथली प्रतियां केवल सबसे बाहरी कंटेनर की प्रतियां हैं।
list.copy
एक उथली प्रति है:
>>> list_of_dict_of_set = [{'foo': set('abc')}]
>>> lodos_copy = list_of_dict_of_set.copy()
>>> lodos_copy[0]['foo'].pop()
'c'
>>> lodos_copy
[{'foo': {'b', 'a'}}]
>>> list_of_dict_of_set
[{'foo': {'b', 'a'}}]
आपको आंतरिक वस्तुओं की प्रतिलिपि नहीं मिलती है। वे एक ही वस्तु हैं - इसलिए जब वे उत्परिवर्तित होते हैं, तो परिवर्तन दोनों कंटेनरों में दिखाई देता है।
गहरी प्रतियां प्रत्येक आंतरिक वस्तु की पुनरावर्ती प्रतियां हैं।
>>> lodos_deep_copy = copy.deepcopy(list_of_dict_of_set)
>>> lodos_deep_copy[0]['foo'].add('c')
>>> lodos_deep_copy
[{'foo': {'c', 'b', 'a'}}]
>>> list_of_dict_of_set
[{'foo': {'b', 'a'}}]
परिवर्तन केवल प्रतिलिपि में मूल में परिलक्षित नहीं होते हैं।
अपरिवर्तनीय वस्तुओं को आमतौर पर कॉपी करने की आवश्यकता नहीं होती है। वास्तव में, यदि आप कोशिश करते हैं, तो पायथन सिर्फ आपको मूल वस्तु देगा:
>>> a_tuple = tuple('abc')
>>> tuple_copy_attempt = a_tuple.copy()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'tuple' object has no attribute 'copy'
टुपल्स के पास एक प्रतिलिपि विधि भी नहीं है, तो आइए इसे एक स्लाइस के साथ आज़माएं:
>>> tuple_copy_attempt = a_tuple[:]
लेकिन हम देखते हैं कि यह एक ही वस्तु है:
>>> tuple_copy_attempt is a_tuple
True
इसी तरह तार के लिए:
>>> s = 'abc'
>>> s0 = s[:]
>>> s == s0
True
>>> s is s0
True
और फ्रोजेनसेट्स के लिए, भले ही उनके पास एक copy
विधि हो:
>>> a_frozenset = frozenset('abc')
>>> frozenset_copy_attempt = a_frozenset.copy()
>>> frozenset_copy_attempt is a_frozenset
True
अगर आपको एक परस्पर आंतरिक वस्तु की प्रतिलिपि बनाने की आवश्यकता है, तो अपरिवर्तनीय वस्तुओं को कॉपी किया जाना चाहिए ।
>>> tuple_of_list = [],
>>> copy_of_tuple_of_list = tuple_of_list[:]
>>> copy_of_tuple_of_list[0].append('a')
>>> copy_of_tuple_of_list
(['a'],)
>>> tuple_of_list
(['a'],)
>>> deepcopy_of_tuple_of_list = copy.deepcopy(tuple_of_list)
>>> deepcopy_of_tuple_of_list[0].append('b')
>>> deepcopy_of_tuple_of_list
(['a', 'b'],)
>>> tuple_of_list
(['a'],)
जैसा कि हम देख सकते हैं, जब कॉपी के आंतरिक ऑब्जेक्ट को उत्परिवर्तित किया जाता है, तो मूल नहीं बदलता है।
कस्टम ऑब्जेक्ट आमतौर पर डेटा को एक __dict__
विशेषता या __slots__
(एक टपल-जैसे मेमोरी संरचना) में संग्रहीत करते हैं ।
एक __copy__
प्रतिलिपि बनाने योग्य वस्तु बनाने के लिए, परिभाषित करें (उथले प्रतियों के लिए) और / या __deepcopy__
(गहरी प्रतियों के लिए)।
from copy import copy, deepcopy
class Copyable:
__slots__ = 'a', '__dict__'
def __init__(self, a, b):
self.a, self.b = a, b
def __copy__(self):
return type(self)(self.a, self.b)
def __deepcopy__(self, memo): # memo is a dict of id's to copies
id_self = id(self) # memoization avoids unnecesary recursion
_copy = memo.get(id_self)
if _copy is None:
_copy = type(self)(
deepcopy(self.a, memo),
deepcopy(self.b, memo))
memo[id_self] = _copy
return _copy
ध्यान दें कि प्रतियों के लिए (या पहचान संख्या) का deepcopy
एक संस्मरण शब्दकोश रखता है id(original)
। पुनरावर्ती डेटा संरचनाओं के साथ अच्छे व्यवहार का आनंद लेने के लिए, सुनिश्चित करें कि आपने पहले से ही प्रतिलिपि नहीं बनाई है, और यदि आपके पास है, तो उसे वापस कर दें।
तो चलिए एक वस्तु बनाते हैं:
>>> c1 = Copyable(1, [2])
और copy
उथली प्रतिलिपि बनाता है:
>>> c2 = copy(c1)
>>> c1 is c2
False
>>> c2.b.append(3)
>>> c1.b
[2, 3]
और deepcopy
अब एक गहरी प्रतिलिपि बनाता है:
>>> c3 = deepcopy(c1)
>>> c3.b.append(4)
>>> c1.b
[2, 3]
के साथ नकल copy.copy()
#!/usr/bin/env python3
import copy
class C():
def __init__(self):
self.x = [1]
self.y = [2]
# It copies.
c = C()
d = copy.copy(c)
d.x = [3]
assert c.x == [1]
assert d.x == [3]
# It's shallow.
c = C()
d = copy.copy(c)
d.x[0] = 3
assert c.x == [3]
assert d.x == [3]
के साथ गहरी प्रतिलिपि copy.deepcopy()
#!/usr/bin/env python3
import copy
class C():
def __init__(self):
self.x = [1]
self.y = [2]
c = C()
d = copy.deepcopy(c)
d.x[0] = 3
assert c.x == [1]
assert d.x == [3]
दस्तावेज़: https://docs.python.org/3/library/copy.html
पायथन 3.6.5 पर परीक्षण किया गया।
मेरा मानना है कि पायथन में वर्गीकृत कई अच्छी तरह से काम करना चाहिए:
def copy(obj):
return type(obj)(obj)
(बेशक, मैं यहां "गहरी प्रतियों" के बारे में बात नहीं कर रहा हूं, जो एक अलग कहानी है, और जो बहुत स्पष्ट अवधारणा नहीं हो सकती है - कितनी गहरी पर्याप्त है?)
पायथन 3 के साथ मेरे परीक्षण के अनुसार, अपरिवर्तनीय वस्तुओं के लिए, जैसे टुपल्स या तार, यह उसी वस्तु को लौटाता है (क्योंकि किसी अपरिवर्तनीय वस्तु की उथली प्रतिलिपि बनाने की कोई आवश्यकता नहीं है), लेकिन सूचियों या शब्दकोशों के लिए यह एक स्वतंत्र उथली प्रतिलिपि बनाता है। ।
बेशक यह विधि केवल उन वर्गों के लिए काम करती है जिनके निर्माणकर्ता तदनुसार व्यवहार करते हैं। संभावित उपयोग के मामले: मानक पायथन कंटेनर क्लास की उथली प्रतिलिपि बनाना।
__init__
पद्धति में इस तरह के सम्मेलन का सम्मान कर सकते हैं । इसलिए, मैंने सोचा कि यह विधि कुछ उद्देश्यों के लिए पर्याप्त हो सकती है। किसी भी मामले में, मुझे इस सुझाव पर जानकारीपूर्ण टिप्पणियों में दिलचस्पी होगी।
class Foo(object): def __init__(self, arg): super(Foo, self).__init__() self.arg = arg
बेसिक पर विचार करें क्योंकि यह हो जाता है। अगर मैं ऐसा करता हूं foo = Foo(3) bar = copy(foo) print(foo.arg) # 3 print(bar.arg) # <__main__.Foo object at ...>
कि आपका copy
फ़ंक्शन कक्षाओं के सबसे बुनियादी हिस्सों के लिए भी टूट गया है। फिर, यह एक साफ चाल है (इसलिए नहीं DV), लेकिन जवाब नहीं।
copy.copy
उथली प्रतियां बनाने के लिए विधि है, लेकिन, शायद भोलेपन से, यह मुझे लगता है कि "उथले प्रतिलिपि निर्माता" प्रदान करना कक्षा की जिम्मेदारी होनी चाहिए। ऐसे मामले में क्यों नहीं के रूप में इंटरफ़ेस के समान किफ प्रदान करना dict
और list
करना? इसलिए, यदि आपकी कक्षा अपनी वस्तुओं की प्रतिलिपि बनाने की ज़िम्मेदारी लेना चाहती है, तो if isinstance(arg, type(self))
खंड को जोड़ना क्यों नहीं __init__
?