पायथन का `copy` मॉड्यूल

पायथन का `copy` मॉड्यूल

यह लेख पायथन के copy मॉड्यूल की व्याख्या करता है।

शैलो और डीप कॉपी के अंतर पर ध्यान केंद्रित करते हुए, हम ऑब्जेक्ट डुप्लिकेशन की बुनियादी तंत्र से लेकर कस्टम क्लास में इसके अनुप्रयोग तक—व्यावहारिक उदाहरणों सहित—स्पष्ट व्याख्या प्रदान करते हैं।

YouTube Video

पायथन का copy मॉड्यूल

Python का copy मॉड्यूल ऑब्जेक्ट डुप्लिकेशन (कॉपी) को संभालने के लिए मानक मॉड्यूल है। उद्देश्य शैलो और डीप कॉपी के अंतर को समझना और कस्टम ऑब्जेक्ट्स के लिए कॉपी करने के व्यवहार को नियंत्रित करने में सक्षम होना है।

बुनियाद: शैलो कॉपी क्या है?

यहाँ हम सूचियों और डिक्शनरी जैसे परिवर्तनशील (mutable) ऑब्जेक्ट्स के लिए शैलो कॉपी का व्यवहार दिखाते हैं। शैलो कॉपी केवल शीर्ष-स्तरीय ऑब्जेक्ट की प्रतिलिपि बनाती है और अंदर के संदर्भों (references) को साझा करती है।

 1# Example: shallow copy with lists and dicts
 2import copy
 3
 4# A nested list
 5original = [1, [2, 3], 4]
 6shallow = copy.copy(original)
 7
 8# Mutate nested element
 9shallow[1].append(99)
10
11print("original:", original)  # nested change visible in original
12print("shallow: ", shallow)

इस कोड में टॉप-लेवल सूची की प्रतिलिपि बनती है, लेकिन भीतरी उप-सूचियाँ संदर्भ के माध्यम से साझा होती हैं, इसलिए shallow[1].append(99) original में भी परिलक्षित होता है। यह शैलो कॉपी का सामान्य व्यवहार है।

डीप कॉपी क्या है?

डीप कॉपी पुनरावृत्त (recursively) तरीके से ऑब्जेक्ट और उसके सभी आंतरिक संदर्भित भागों की प्रतिलिपि बनाती है, जिससे एक स्वतंत्र ऑब्जेक्ट तैयार होता है। इसे तब उपयोग करें जब आप जटिल नेस्टेड संरचनाओं की सुरक्षित प्रतिलिपि बनाना चाहते हों।

 1# Example: deep copy with nested structures
 2import copy
 3
 4original = [1, [2, 3], {'a': [4, 5]}]
 5deep = copy.deepcopy(original)
 6
 7# Mutate nested element of the deep copy
 8deep[1].append(100)
 9deep[2]['a'].append(200)
10
11print("original:", original)  # original remains unchanged
12print("deep:    ", deep)

इस उदाहरण में, deep में किए गए परिवर्तन original को प्रभावित नहीं करते। deepcopy पूरे ऑब्जेक्ट ग्राफ़ की कॉपी बनाता है और एक स्वतंत्र प्रतिरूप (replica) देता है।

किसका उपयोग करें, यह कैसे तय करें

कौन-सी कॉपी उपयोग करनी है, यह ऑब्जेक्ट की संरचना और आपके उद्देश्य पर निर्भर होना चाहिए। यदि आप नहीं चाहते कि आंतरिक परिवर्तनशील तत्वों के परिवर्तन मूल ऑब्जेक्ट को प्रभावित करें, तो deepcopy उपयुक्त है। क्योंकि यह पूरे ऑब्जेक्ट की पुनरावृत्त प्रतिलिपि बनाता है और पूर्णतः स्वतंत्र प्रति तैयार करता है।

दूसरी ओर, यदि केवल शीर्ष-स्तरीय ऑब्जेक्ट की प्रतिलिपि बनाना पर्याप्त है और आप गति तथा मेमोरी दक्षता को महत्व देते हैं, तो copy (शैलो कॉपी) अधिक उपयुक्त है।

  • आप चाहते हैं कि आंतरिक परिवर्तनशील तत्वों में बदलाव करने पर मूल ऑब्जेक्ट न बदले → deepcopy का उपयोग करें।
  • केवल शीर्ष स्तर की प्रतिलिपि पर्याप्त है और आप प्रदर्शन (गति/मेमोरी) को प्राथमिकता देना चाहते हैं → copy (शैलो कॉपी) का उपयोग करें।

बिल्ट-इन और इम्यूटेबल ऑब्जेक्ट्स का प्रबंधन

इम्यूटेबल ऑब्जेक्ट्स (जैसे int, str, और वे ट्यूपल जिनकी सामग्री इम्यूटेबल है) को आमतौर पर कॉपी करने की आवश्यकता नहीं होती। copy.copy उपयुक्त होने पर वही ऑब्जेक्ट वापस कर सकता है।

 1# Example: copying immutables
 2import copy
 3
 4a = 42
 5b = copy.copy(a)
 6print(a is b)  # True for small ints (implementation detail)
 7
 8s = "hello"
 9t = copy.deepcopy(s)
10print(s is t)  # True (strings are immutable)

क्योंकि इम्यूटेबल ऑब्जेक्ट्स की कॉपी करने से दक्षता में बहुत कम लाभ मिलता है, इसलिए उसी ऑब्जेक्ट का पुनः उपयोग किया जा सकता है। एप्लिकेशन डिज़ाइन में इसके बारे में आपको शायद ही चिंता करने की आवश्यकता पड़ती है।

कस्टम क्लास: __copy__ और __deepcopy__ को परिभाषित करना

यदि आपकी क्लास के लिए डिफ़ॉल्ट कॉपी करना अपेक्षित परिणाम नहीं देता, तो आप अपनी कॉपी लॉजिक प्रदान कर सकते हैं। यदि आप __copy__ और __deepcopy__ परिभाषित करते हैं, तो copy.copy और copy.deepcopy उनका उपयोग करेंगे।

 1# Example: customizing copy behavior
 2import copy
 3
 4class Node:
 5    def __init__(self, value, children=None):
 6        self.value = value
 7        self.children = children or []
 8
 9    def __repr__(self):
10        return f"Node({self.value!r}, children={self.children!r})"
11
12    def __copy__(self):
13        # Shallow copy: create new Node, but reuse children list reference
14        new = self.__class__(self.value, self.children)
15        return new
16
17    def __deepcopy__(self, memo):
18        # Deep copy: copy value and deepcopy each child
19        new_children = [copy.deepcopy(child, memo) for child in self.children]
20        new = self.__class__(copy.deepcopy(self.value, memo), new_children)
21        memo[id(self)] = new
22        return new
  • __copy__ और __deepcopy__ को लागू करके, आप कक्षा-विशिष्ट कॉपी करने के व्यवहार को लचीले ढंग से नियंत्रित कर सकते हैं। उदाहरण के लिए, आप ऐसे मामलों को संभाल सकते हैं जहाँ कुछ गुण उसी ऑब्जेक्ट का संदर्भ दें (उसे साझा करें), जबकि अन्य गुणों को पूरी तरह नए ऑब्जेक्ट के रूप में प्रतिलिपि किया जाए।
  • __deepcopy__ को दिया गया memo आर्ग्युमेंट एक डिक्शनरी है, जो पुनरावर्ती कॉपी के दौरान पहले से संसाधित ऑब्जेक्ट्स को दर्ज करता है और परिपत्र संदर्भों के कारण होने वाले अनंत लूप्स को रोकता है।
 1# Build tree
 2root_node = Node('root', [Node('child1'), Node('child2')])
 3
 4shallow_copy = copy.copy(root_node)   # shallow copy
 5deep_copy = copy.deepcopy(root_node)  # deep copy
 6
 7# Modify children
 8# affects both root_node and shallow_copy
 9shallow_copy.children.append(Node('child_shallow'))
10# affects deep_copy only
11deep_copy.children.append(Node('child_deep'))
12
13# Print results
14print("root_node:", root_node)
15print("shallow_copy:", shallow_copy)
16print("deep_copy:", deep_copy)
  • इस कोड में, चर shallow_copy 'शैलो कॉपी' के माध्यम से बनाया जाता है, इसलिए ऑब्जेक्ट के केवल शीर्ष स्तर की प्रतिलिपि बनती है, और इसके भीतर जिन ऑब्जेक्ट्स का यह संदर्भ देता है (इस मामले में, children सूची) मूल root_node के साथ साझा होते हैं। परिणामस्वरूप, जब आप shallow_copy में नया नोड जोड़ते हैं, तो साझा की गई children सूची अपडेट हो जाती है और यह परिवर्तन root_node की सामग्री में भी परिलक्षित होता है।
  • दूसरी ओर, चर deep_copy 'डीप कॉपी' के माध्यम से बनाया जाता है, इसलिए आंतरिक संरचना की पुनरावर्ती रूप से प्रतिलिपि बनती है, और root_node से पूरी तरह स्वतंत्र एक वृक्ष बनता है। इसलिए, भले ही आप deep_copy में नया नोड जोड़ें, यह root_node को प्रभावित नहीं करता।

चक्रीय संदर्भ (recursive ऑब्जेक्ट्स) और memo का महत्व

जब कोई जटिल ऑब्जेक्ट ग्राफ़ स्वयं को संदर्भित करता है (चक्रीय संदर्भ), तो deepcopy पहले से कॉपी किए गए ऑब्जेक्ट्स को ट्रैक करने और अनंत लूप से बचाने के लिए memo डिक्शनरी का उपयोग करता है।

 1# Example: recursive list and deepcopy memo demonstration
 2import copy
 3
 4a = []
 5b = [a]
 6a.append(b)  # a -> [b], b -> [a]  (cycle)
 7
 8# deepcopy can handle cycles
 9deep = copy.deepcopy(a)
10print("deep copy succeeded, length:", len(deep))
  • आंतरिक रूप से, deepcopy memo का उपयोग पहले से डुप्लिकेट किए गए ऑब्जेक्ट्स को संदर्भित करने के लिए करता है, जिससे चक्र मौजूद होने पर भी सुरक्षित कॉपी संभव होती है। जब आप मैन्युअल रूप से रिकर्शन कर रहे हों, तो आपको इसी तरह की व्यवस्था की आवश्यकता होती है।

copyreg और सीरियलाइज़ेशन-शैली की कस्टम कॉपी (उन्नत)

यदि आप लाइब्रेरीज़ के साथ समन्वय में विशेष कॉपी व्यवहार पंजीकृत करना चाहते हैं, तो आप मानक copyreg मॉड्यूल का उपयोग करके यह पंजीकृत कर सकते हैं कि ऑब्जेक्ट्स कैसे (पुनः)निर्मित किए जाते हैं। यह जटिल ऑब्जेक्ट्स और C एक्सटेंशन प्रकारों के लिए उपयोगी है।

 1# Example: using copyreg to customize pickling/copy behavior (brief example)
 2import copy
 3import copyreg
 4
 5class Wrapper:
 6    def __init__(self, data):
 7        self.data = data
 8
 9def reduce_wrapper(obj):
10    # Return callable and args so object can be reconstructed
11    return (Wrapper, (obj.data,))
12
13copyreg.pickle(Wrapper, reduce_wrapper)
14
15w = Wrapper([1, 2, 3])
16w_copy = copy.deepcopy(w)
17print("w_copy.data:", w_copy.data)
  • copyreg का उपयोग करके, आप ऐसे पुनर्निर्माण नियम प्रदान कर सकते हैं जो pickle और deepcopy दोनों को प्रभावित करते हैं। यह एक उन्नत API है, और अधिकांश मामलों में __deepcopy__ पर्याप्त होता है।

व्यावहारिक सावधानियाँ और संभावित त्रुटियाँ

copy मॉड्यूल का उपयोग करते समय सही व्यवहार सुनिश्चित करने के लिए कई महत्वपूर्ण बिंदु हैं। नीचे हम विकास के दौरान मिलने वाली सामान्य गलतियों और उनसे बचने के तरीकों की व्याख्या करते हैं।

  • प्रदर्शन deepcopy काफी मेमोरी और CPU खपा सकता है, इसलिए ध्यान से विचार करें कि क्या यह वाकई आवश्यक है।
  • वे तत्व संभालना जिन्हें आप साझा रखना चाहते हैं यदि आप कुछ एट्रिब्यूट्स, जैसे बड़े कैश, को साझा रखना चाहते हैं, तो __deepcopy__ के भीतर उनके संदर्भों की कॉपी जानबूझकर न करें।
  • इम्यूटेबल आंतरिक स्टेट यदि आप आंतरिक रूप से इम्यूटेबल डेटा रखते हैं, तो कॉपी करना अनावश्यक हो सकता है।
  • थ्रेड्स और बाहरी संसाधन ऐसे संसाधन जिन्हें कॉपी नहीं किया जा सकता, जैसे सॉकेट्स और फ़ाइल हैंडल, की कॉपी या तो निरर्थक है या त्रुटियाँ उत्पन्न करेगी, इसलिए डिज़ाइन द्वारा उनकी कॉपी से बचना चाहिए।

व्यावहारिक उदाहरण: डिक्शनरी को सुरक्षित रूप से अद्यतन करने का एक पैटर्न

किसी जटिल कॉन्फ़िगरेशन ऑब्जेक्ट को अपडेट करते समय, यह उदाहरण मूल सेटिंग्स की सुरक्षा के लिए deepcopy का उपयोग करता है।

 1# Example: safely update a nested configuration using deepcopy
 2import copy
 3
 4default_config = {
 5    "db": {"host": "localhost", "ports": [5432]},
 6    "features": {"use_cache": True, "cache_sizes": [128, 256]},
 7}
 8
 9# Create a working copy to modify without touching defaults
10working = copy.deepcopy(default_config)
11working["db"]["ports"].append(5433)
12working["features"]["cache_sizes"][0] = 512
13
14print("default_config:", default_config)
15print("working:", working)

deepcopy का उपयोग करके, आप डिफ़ॉल्ट सेटिंग्स को नुकसान पहुँचाने के जोखिम के बिना सुरक्षित रूप से व्युत्पन्न कॉन्फ़िगरेशन बना सकते हैं। यह विशेष रूप से कॉन्फ़िगरेशन जैसी नेस्टेड परिवर्तनशील संरचनाओं के लिए उपयोगी है।

सर्वोत्तम अभ्यास

copy मॉड्यूल को सुरक्षित और प्रभावी ढंग से उपयोग करने के लिए, निम्नलिखित व्यावहारिक दिशानिर्देशों को ध्यान में रखना महत्वपूर्ण है।

  • परिवर्तन होंगे या नहीं और उनकी परिधि क्या होगी, इसके आधार पर शैलो और डीप कॉपी में से चुनें।
  • अपेक्षित व्यवहार पाने के लिए कस्टम क्लास में __copy__ और __deepcopy__ लागू करें।
  • क्योंकि डीप कॉपी महँगी होती है, जहाँ संभव हो डिज़ाइन के माध्यम से कॉपी की आवश्यकता कम करें। अन्य तकनीकों के साथ-साथ, इम्यूटेबिलिटी और स्पष्ट क्लोन मेथड्स पर विचार करें।
  • चक्रीय संदर्भों से निपटते समय, या तो deepcopy का लाभ लें या मैन्युअल रूप से मेमो जैसी व्यवस्था प्रदान करें।
  • ऐसा डिज़ाइन करें कि फ़ाइल हैंडल और थ्रेड जैसे बाहरी संसाधनों की प्रतिलिपि न बने।

निष्कर्ष

copy मॉड्यूल Python में ऑब्जेक्ट डुप्लिकेशन के लिए मानक उपकरण है। शैलो और डीप कॉपी के अंतर को ठीक से समझकर और आवश्यकता होने पर कस्टम कॉपी व्यवहार लागू करके, आप सुरक्षित और अनुमानित ढंग से डुप्लिकेशन कर सकते हैं। डिज़ाइन चरण में यह स्पष्ट करके कि कॉपी वास्तव में आवश्यक है या नहीं और क्या साझा रहना चाहिए, आप अनावश्यक बग्स और प्रदर्शन समस्याओं से बच सकते हैं।

आप हमारे YouTube चैनल पर Visual Studio Code का उपयोग करके ऊपर दिए गए लेख के साथ आगे बढ़ सकते हैं। कृपया YouTube चैनल को भी देखें।

YouTube Video