উত্তর:
কোনও সামগ্রীর সম্পূর্ণ স্বতন্ত্র অনুলিপি পেতে আপনি 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
ফাংশনটি এমনকি ক্লাসের সর্বাধিক প্রাথমিকের জন্যও নষ্ট হয়ে গেছে। আবার, এটি একটি ঝরঝরে কৌশল (কোনও ডিভি নয়), তবে কোনও উত্তর নয়।
copy.copy
অগভীর অনুলিপিগুলি তৈরি করার পদ্ধতি রয়েছে, তবে সম্ভবত নির্লজ্জভাবে মনে হয়, "অগভীর অনুলিপি নির্মাণকারী" সরবরাহ করার দায়িত্ব শ্রেণীর হওয়া উচিত। এ ক্ষেত্রে কেন একই ধরণের ইন্টারফেসের ইন্টারফেস সরবরাহ করবেন না dict
এবং list
করবেন না কেন? সুতরাং, যদি আপনার শ্রেণি এর বিষয়গুলি অনুলিপি করার জন্য দায় নিতে চায় তবে কেন একটি if isinstance(arg, type(self))
ধারা যুক্ত করা যায় না __init__
?