मैं पायथन में किसी ऑब्जेक्ट की कॉपी कैसे बना सकता हूं?


200

मैं एक वस्तु की एक प्रति बनाना चाहूंगा। मैं चाहता हूं कि नई वस्तु पुरानी वस्तु (खेतों के मूल्यों) के सभी गुणों के अधिकारी हो। लेकिन मैं स्वतंत्र वस्तुएं रखना चाहता हूं। इसलिए, यदि मैं नई वस्तु के क्षेत्रों के मूल्यों को बदलता हूं, तो पुरानी वस्तु उससे प्रभावित नहीं होनी चाहिए।

जवाबों:


180

किसी ऑब्जेक्ट की पूरी तरह से स्वतंत्र प्रतिलिपि प्राप्त करने के लिए आप copy.deepcopy()फ़ंक्शन का उपयोग कर सकते हैं ।

उथले और गहरी नकल के बारे में अधिक जानकारी के लिए कृपया इस प्रश्न के अन्य उत्तरों और संबंधित प्रश्न के इस उत्तर में अच्छी व्याख्या देखें ।


2
: यहाँ मेटा चर्चा - यह जवाब के रूप में "नहीं एक जवाब", चिह्नित किया गया था नष्ट कर दिया, और हटाया नहीं गया meta.stackoverflow.com/questions/377844/...
हारून हॉल

@AaronHall मुझे बताने के लिए धन्यवाद! यह निश्चित रूप से मेरे द्वारा लिखा गया सबसे बड़ा जवाब नहीं है, लेकिन मैं इस फैसले से सहमत हूं कि इसे जबरन हटाया नहीं जाना चाहिए। मैं इसे थोड़ा ब्रश करूंगा, लेकिन चूंकि पहले से ही सभी विवरणों के साथ उत्तर हैं (विशेष रूप से आपका), मैं इसे छोटा रखूंगा।
स्वेन मार्नाच

70

मैं पायथन में किसी ऑब्जेक्ट की कॉपी कैसे बना सकता हूं?

इसलिए, यदि मैं नई वस्तु के क्षेत्रों के मूल्यों को बदलता हूं, तो पुरानी वस्तु उससे प्रभावित नहीं होनी चाहिए।

तुम तो एक उत्परिवर्तनीय वस्तु का मतलब है।

पायथन 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]

11

के साथ नकल 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 पर परीक्षण किया गया।


-2

मेरा मानना ​​है कि पायथन में वर्गीकृत कई अच्छी तरह से काम करना चाहिए:

def copy(obj):
    return type(obj)(obj)

(बेशक, मैं यहां "गहरी प्रतियों" के बारे में बात नहीं कर रहा हूं, जो एक अलग कहानी है, और जो बहुत स्पष्ट अवधारणा नहीं हो सकती है - कितनी गहरी पर्याप्त है?)

पायथन 3 के साथ मेरे परीक्षण के अनुसार, अपरिवर्तनीय वस्तुओं के लिए, जैसे टुपल्स या तार, यह उसी वस्तु को लौटाता है (क्योंकि किसी अपरिवर्तनीय वस्तु की उथली प्रतिलिपि बनाने की कोई आवश्यकता नहीं है), लेकिन सूचियों या शब्दकोशों के लिए यह एक स्वतंत्र उथली प्रतिलिपि बनाता है। ।

बेशक यह विधि केवल उन वर्गों के लिए काम करती है जिनके निर्माणकर्ता तदनुसार व्यवहार करते हैं। संभावित उपयोग के मामले: मानक पायथन कंटेनर क्लास की उथली प्रतिलिपि बनाना।


यह साफ-सुथरा और सभी है, लेकिन सवाल का जवाब नहीं देता क्योंकि आपका कॉपी फंक्शन कस्टम क्लासेस के लिए फेल है और सवाल ऑब्जेक्ट्स का था ।
जेरेड स्मिथ

@JaredSmith, यह नहीं कहा गया था कि प्रश्न सभी वस्तुओं के बारे में था । यह भी स्पष्ट नहीं था कि यह गहरी या उथली प्रतिलिपि के बारे में था (मैं सामान्य उथले को मान लूंगा, लेकिन स्वीकृत उत्तर गहरे एक के बारे में है)। कस्टम कक्षाओं के रूप में, यदि वे आपके हैं, तो आप उनकी __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), लेकिन जवाब नहीं।
जारेद स्मिथ

@JaredSmith, मैंने देखा कि copy.copyउथली प्रतियां बनाने के लिए विधि है, लेकिन, शायद भोलेपन से, यह मुझे लगता है कि "उथले प्रतिलिपि निर्माता" प्रदान करना कक्षा की जिम्मेदारी होनी चाहिए। ऐसे मामले में क्यों नहीं के रूप में इंटरफ़ेस के समान किफ प्रदान करना dictऔर listकरना? इसलिए, यदि आपकी कक्षा अपनी वस्तुओं की प्रतिलिपि बनाने की ज़िम्मेदारी लेना चाहती है, तो if isinstance(arg, type(self))खंड को जोड़ना क्यों नहीं __init__?
एलेक्सी

1
क्योंकि आपके पास हमेशा उन वर्गों पर नियंत्रण नहीं होता है जो आप अपने द्वारा परिभाषित किए गए तरीकों का उपयोग करते हैं। वे केवल एक उदाहरण के रूप में, C प्रोग्राम हो सकते हैं जिसमें पायथन बाइंडिंग (जैसे GTK, ओपनलैप, कोर के हिस्से) हैं। इस बात का जिक्र नहीं है कि अगर आपने थर्ड पार्टी लाइब्रेरी ली है और हर क्लास में कॉपी मेथड जोड़े हैं, तो आप इसे अपने डिपेंडेंट मैनेजमेंट में कैसे बुनेंगे?
जारेड स्मिथ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.