পাইথনে আমি কীভাবে কোনও বস্তুর অনুলিপি তৈরি করতে পারি?


199

আমি একটি অবজেক্টের একটি অনুলিপি তৈরি করতে চাই। আমি চাই নতুন জিনিসটি পুরানো বস্তুর সমস্ত ক্ষেত্র (ক্ষেত্রের মান) রাখুক। তবে আমি স্বাধীন জিনিস পেতে চাই। সুতরাং, আমি যদি নতুন অবজেক্টের ক্ষেত্রগুলির মানগুলি পরিবর্তন করি তবে পুরানো বস্তুটি সে দ্বারা প্রভাবিত হবে না।

উত্তর:


179

কোনও সামগ্রীর সম্পূর্ণ স্বতন্ত্র অনুলিপি পেতে আপনি copy.deepcopy()ফাংশনটি ব্যবহার করতে পারেন ।

অগভীর এবং গভীর অনুলিপি সম্পর্কে আরও তথ্যের জন্য দয়া করে এই প্রশ্নের অন্যান্য উত্তরগুলি এবং সম্পর্কিত প্রশ্নের উত্তরটিতে সুন্দর ব্যাখ্যা দেখুন ।


2
এই উত্তরটিকে "উত্তর নয়" হিসাবে চিহ্নিত করা হয়েছে, মুছে ফেলা হয়েছে এবং মুছে ফেলা হয়েছে - মেটা আলোচনা এখানে করা হয়েছে: meta.stackoverflow.com/questions/377844/…
অ্যারন হল

@ অ্যারোনহেল আমাকে জানাতে ধন্যবাদ! এটি অবশ্যই আমার লেখা সবচেয়ে বড় উত্তর নয়, তবে জোর করে মুছে ফেলা উচিত নয় এমন সিদ্ধান্তের সাথে আমি একমত। আমি এটি কিছুটা ব্রাশ করব, তবে যেহেতু ইতিমধ্যে সমস্ত বিবরণের উত্তর রয়েছে (বিশেষত আপনার), তাই আমি এটি সংক্ষিপ্ত রাখব।
সোভেন মারনাচ

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]

10

সাথে অগভীর কপি 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 এর সাথে আমার পরীক্ষাগুলি অনুসারে, টিপলস বা স্ট্রিংয়ের মতো অপরিবর্তনীয় বস্তুর জন্য, এটি একই জিনিসটি ফেরত দেয় (কারণ কোনও অপরিবর্তনীয় বস্তুর অগভীর অনুলিপি তৈরি করার প্রয়োজন নেই), তবে তালিকা বা অভিধানগুলির জন্য এটি একটি স্বাধীন অগভীর অনুলিপি তৈরি করে ।

অবশ্যই এই পদ্ধতিটি কেবল সেই শ্রেণীর জন্য কাজ করে যার নির্মাতারা সেই অনুযায়ী আচরণ করে। সম্ভাব্য ব্যবহারের কেস: একটি স্ট্যান্ডার্ড পাইথন ধারক শ্রেণীর অগভীর অনুলিপি তৈরি করা।


এটি পরিষ্কার এবং সব কিছু, তবে প্রশ্নের উত্তর দেয় না কারণ আপনার অনুলিপি ফাংশনটি কাস্টম ক্লাসগুলির জন্য ব্যর্থ হয়েছে এবং প্রশ্নটি বস্তুগুলি সম্পর্কে ছিল ।
জারেড স্মিথ

@ জারেডস্মিথ, এটি বলা হয়নি যে প্রশ্নটি সমস্ত বস্তু সম্পর্কে about এটি গভীর বা অগভীর অনুলিপি সম্পর্কে ছিল কিনা তা এখনও স্পষ্ট ছিল না (আমি স্বাভাবিক অগভীর একটিকে গ্রহণ করব তবে গ্রহণযোগ্য উত্তরটি গভীর উত্তর সম্পর্কে)। কাস্টম ক্লাস হিসাবে, যদি সেগুলি আপনার হয়, আপনি তাদের __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ফাংশনটি এমনকি ক্লাসের সর্বাধিক প্রাথমিকের জন্যও নষ্ট হয়ে গেছে। আবার, এটি একটি ঝরঝরে কৌশল (কোনও ডিভি নয়), তবে কোনও উত্তর নয়।
জ্যারেড স্মিথ

@ জ্যারেডস্মিথ, আমি দেখেছি যে copy.copyঅগভীর অনুলিপিগুলি তৈরি করার পদ্ধতি রয়েছে, তবে সম্ভবত নির্লজ্জভাবে মনে হয়, "অগভীর অনুলিপি নির্মাণকারী" সরবরাহ করার দায়িত্ব শ্রেণীর হওয়া উচিত। এ ক্ষেত্রে কেন একই ধরণের ইন্টারফেসের ইন্টারফেস সরবরাহ করবেন না dictএবং listকরবেন না কেন? সুতরাং, যদি আপনার শ্রেণি এর বিষয়গুলি অনুলিপি করার জন্য দায় নিতে চায় তবে কেন একটি if isinstance(arg, type(self))ধারা যুক্ত করা যায় না __init__?
অ্যালেক্সি

1
যেহেতু আপনি যে ক্লাসগুলি নির্ধারণ করেন সেভাবে আপনি যেভাবে ক্লাস করেন সেগুলি নিয়ে আপনার সর্বদা নিয়ন্ত্রণ নেই। তারা, যেমন একটি উদাহরণ হিসাবে সি প্রোগ্রাম হতে পারে যা পাইথন বাইন্ডিংস (যেমন জিটিকে, ওপেনপ্রল, মূল অংশ) রয়েছে। আপনি কোনও তৃতীয় পক্ষের গ্রন্থাগার নিয়েছেন এবং প্রতি ক্লাসে অনুলিপি পদ্ধতিগুলি যুক্ত করেছেন তা উল্লেখ করার দরকার নেই, আপনি কীভাবে আপনার নির্ভরতা পরিচালনার ক্ষেত্রে এটি বুনতে যাচ্ছেন?
জারেড স্মিথ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.