در این آموزش ، شما در مورد کپی کردن اشیاء در پایتون با استفاده از copy ماژول ما روش استفاده از copy ماژول و چه موقع از آن استفاده کنید copy() عملکرد و deepcopy() عملکرد ، بستگی به روی سناریو شما همچنین می آموزید که کدام روش کپی کردن برای اشیاء قابل تغییر و تغییر ناپذیر مناسب است.

با پایان این آموزش ، خواهید فهمید:

  • چیست copy ماژول؟

  • تفاوت بین کپی و ارجاع.

  • تفاوت یک کپی عمیق و یک کپی کم عمق.

  • چگونه در واقع کپی های کم عمق و اشیاء کپی عمیق در پایتون.

  • تفاوت در مراجعه به اشیاء تغییر ناپذیر و اشیاء قابل تغییر.

پیش نیازهای

برای به دست آوردن بیشترین استفاده از این آموزش ، باید درک اساسی از موارد زیر داشته باشید:

  1. دانش اساسی برنامه نویسی و اصطلاحات آن (مانند اشیاء ، آدرس های حافظه و غیره روی)

  2. دانش اساسی برنامه نویسی پایتون ، به ویژه (برای این آموزش) ،

    • عمل id(): آدرس حافظه شیء را که به عنوان آرگومان تصویب شده است ، خروجی می کند.

    • ساختار داده ها: فرهنگ لغت ها و لیست ها.

    • ماژول ها: واردات و استفاده از آنها در برنامه. درک اساسی روش ها و کارکردها.

فهرست مطالب:

  1. ماژول کپی در پایتون چیست؟

    • چرا نمی توانیم فقط از اپراتور واگذاری استفاده کنیم؟
  2. روش کپی کردن صحیح اشیاء در پایتون

  3. اطلاعات بیشتر در مورد کپی کردن اشیاء در پایتون

  4. خلاصه

چیست copy ماژول؟

در copy ماژول یک ماژول داخلی در پایتون است که در درجه اول برای کپی کردن اشیاء در پایتون استفاده می شود. این امکان را به شما می دهد تا در یک شیء قابل تغییر تغییراتی ایجاد کنید و آن را به عنوان یک نسخه متفاوت در حافظه ذخیره کنید. بنابراین اساساً ، کپی از شیء اصلی را ایجاد می کند و آن را در یک مکان حافظه متفاوت ذخیره می کند.

چرا ما فقط نمی توانیم از اپراتور واگذاری استفاده کنیم (=) برای کپی کردن اشیاء؟

اگر برای کپی کردن اشیاء از اپراتور واگذاری استفاده کنیم ، در واقع اینگونه نیست کپی کردن شیء – در عوض ، اتصال بین جسم و شناسه ایجاد می کند. این بدان معنی است که اگر شیء اصلی در مکان حافظه قرار بگیرد x، سپس شناسه ای که در آن سعی کردیم شی را با استفاده از آن کپی کنیم = اپراتور همچنین به همان مکان حافظه ، یعنی مکان اشاره خواهد کرد xبشر

اکنون ، این ممکن است هنگام دستکاری جنبه های مختلف داده ها مشکلاتی ایجاد کند ، زیرا تغییراتی که در شی انجام می دهیم در اتصال آن نیز منعکس می شود.

قبل از پریدن به کد ، ابتدا به تفاوت بین کپی و ارجاع نگاه می کنیم:

  • کپی کردن: ایجاد یک نسخه به تکرار هدف هدف و ذخیره جداگانه در حافظه اشاره دارد و آن را به یک شیء مستقل با همان داده ها تبدیل می کند.

  • ارجاع: مراجعه به یک شیء به اشاره به همان آدرس حافظه که در آن شیء هدف ذخیره می شود ، اشاره دارد. شیء ارجاع شده فقط نام دیگری است (که ما به عنوان “نام مستعار” در برنامه نویسی می نامیم تا شیء اصلی را صدا کند.

بیایید این را با یک مثال درک کنیم:

# creating a dictionary object.
d1 = {
    'A' : 1,
    'B' : 2,
    'C' : 3
}

# using assignment operator to copy d1 in d2.
d2=d1

# printing both the dictionaries.
print(f'd1 = {d1} \nd2 = {d2}')

خروجی:

d1 = {‘a’: 1 ، ‘b’: 2 ، ‘c’: 3}

d2 = {‘a’: 1 ، ‘b’: 2 ، ‘c’: 3}

از مثال بالا ، ممکن است به نظر برسد که فرهنگ لغت به صورت متغیر کپی شده است d2 – اما در واقعیت ، این فقط به شیء ذخیره شده در متغیر اشاره دارد d1بشر در این حالت ، متغیر d2 فقط یک نام مستعار یا مرجع به همان شی است d1بشر ما می توانیم این را به شرح زیر ثابت کنیم:

d1 = {
    'A' : 1,
    'B' : 2,
    'C' : 3
}

d2=d1

d1['D'] = 4 # added a key-value pair in d1

print(f'd1 = {d1} \nd2 = {d2}')

خروجی:

d1 = {‘a’: 1 ، ‘b’: 2 ، ‘c’: 3 ، ‘d’: 4}

d2 = {‘a’: 1 ، ‘b’: 2 ، ‘c’: 3 ، ‘d’: 4}

اکنون ، در کد فوق ، ما یک جفت ارزش کلیدی را در فرهنگ لغت ضمیمه کردیم d1 فقط – اما این تغییر در فرهنگ لغت دیده می شود d2، هم از این رو ، بدیهی است که هر دو شناسه به یک شیء یکسان مراجعه می کردند.

از این ما این را می فهمیم ، اپراتور واگذاری = می تواند برای مراجعه به اشیاء استفاده شود و ما نمی توانیم از آن برای کپی کردن اشیاء به معنای واقعی استفاده کنیم.

روش کپی کردن صحیح اشیاء در پایتون

از آنجا که اکنون تفاوت بین کپی و ارجاع را درک می کنید ، بیایید ببینیم که چگونه می توانید اشیاء را در پایتون کپی کنید. برای این کار ، ما از copy ماژول (که قبلاً ذکر شد).

پیشنهاد می‌کنیم بخوانید:  روش ارسال ایمیل با Django

اکنون ، قبل از استفاده از این ماژول ، باید تفاوت بین یک کپی عمیق و یک کپی کم عمق را درک کنید.

  • کپی عمیق: در حالی که با اشیاء مرکب کار می کنید (همچنین به عنوان شناخته می شود container اشیاء یا اشیاء کامپوزیت) ، کپی عمیق به معنای ایجاد یک کپی از اشیاء داخلی و همچنین شیء بیرونی است.

  • کپی کم عمق: در حین کار با اشیاء مرکب ، کپی کردن کم عمق به کپی کردن تنها شیء بیرونی و مراجعه به اشیاء داخلی اشاره دارد.

یادداشت: اشیاء مرکب اشیاء هستند که دارای اشیاء دیگری در داخل آنها هستند.

بیایید با اجرای آنها در یک برنامه ، تفاوت بین نسخه های عمیق و کم عمق را درک کنیم:

import copy # importing copy module

# creating a composite object
categories = {
    'Fruits' : ['Apple', 'Banana', 'Mango'],
    'Flowers' : ['Rose', 'Sunflower', 'Tulip'],
}

# copying the object by using the copy() function of the copy module
categories_copy = copy.copy(categories)

print(f'Categories = {categories}\nCategories (Copied) = {categories_copy}')

خروجی:

دسته بندی = {“میوه”: [‘Apple’, ‘Banana’, ‘Mango’]، “گل”: [‘Rose’, ‘Sunflower’, ‘Tulip’]}

دسته بندی ها (کپی شده) = {“میوه”: [‘Apple’, ‘Banana’, ‘Mango’]، “گل”: [‘Rose’, ‘Sunflower’, ‘Tulip’]}

در مثال بالا ، ما یک شیء کامپوزیت به نام ساختیم categories این لیست به عنوان اشیاء داخلی است. سپس ، ما از copy() عملکرد copy ماژول برای کپی کردن شیء اصلی. همچنین ، از آنجا copy ماژول داخلی است ، دیگر نیازی به نصب آن به صورت دستی نیست! اکنون ، هر دو شیء مشابه به نظر می رسند.

در مرحله بعد ، بیایید شیء اصلی را اصلاح کنیم تا ببینیم آیا شیء واقعاً کپی شده است یا فقط ارجاع شده است:

import copy

categories = {
    'Fruits' : ['Apple', 'Banana', 'Mango'],
    'Flowers' : ['Rose', 'Sunflower', 'Tulip'],
}

categories_copy = copy.copy(categories)

# added a key-value pair in the original dictionary.
categories['Color'] = ['Red', 'Yellow', 'Blue']

print(f'Categories = {categories}\nCategories (Copied) = {categories_copy}')

خروجی:

دسته بندی = {“میوه”: [‘Apple’, ‘Banana’, ‘Mango’]، “گل”: [‘Rose’, ‘Sunflower’, ‘Tulip’]، “رنگ”: [‘Red’, ‘Yellow’, ‘Blue’]}

دسته بندی ها (کپی شده) = {“میوه”: [‘Apple’, ‘Banana’, ‘Mango’]، “گل”: [‘Rose’, ‘Sunflower’, ‘Tulip’]}

در اینجا ، می توانیم ببینیم که حتی وقتی فرهنگ لغت اصلی را تغییر دادیم ، فرهنگ لغت کپی شده (ذخیره شده در متغیر categories_copy) همان باقی مانده است. این بدان معنی است که ما فرهنگ لغت را با موفقیت در یک مکان حافظه متفاوت کپی کردیم.

اما ما کم عمق فرهنگ لغت را کپی کردیم. ما می دانیم که ، برای یک شیء کامپوزیت کپی شده کم عمق ، اشیاء داخلی در همان مکان حافظه به عنوان شیء کامپوزیت اصلی نشان می دهند. این را می توانید در مثال زیر مشاهده کنید:

import copy

categories = {
    'Fruits' : ['Apple', 'Banana', 'Mango'],
    'Flowers' : ['Rose', 'Sunflower', 'Tulip'],
}

categories_copy = copy.copy(categories)

# checking if the inner object list 'Fruits' of both the dictionaries point to same memory address.
print(f"""
Do 'categories' and 'categories_copy' inner object share same memory address? 
--> {id(categories_copy['Fruits']) == id(categories['Fruits'])}
""")

# checking if the outer objects (dictionaries) point to same memory address.
print(f"""
Do 'categories' and 'categories_copy' outer object share same memory address? 
--> {id(categories_copy) == id(categories)}
""")

خروجی:

آیا “دسته بندی ها” و “دسته بندی_کپی” شیء داخلی آدرس حافظه مشابه را به اشتراک می گذارد؟

-> درست

آیا “دسته بندی ها” و “دسته بندی_کپی” شیء بیرونی آدرس حافظه مشابه را به اشتراک می گذارند؟

-> نادرست

در کد فوق ، از همان نمونه قبلی استفاده کردیم. سپس ، ما از عملکرد داخلی استفاده کردیم id() برای استخراج و مقایسه آدرس حافظه هر دو فرهنگ لغت.

برای اشیاء داخلی ، آدرس حافظه یکسان است. اما اشیاء بیرونی در مکان های مختلف حافظه قرار دارند. بنابراین ، می توانیم بگوییم که در حالی که اشیاء کپی کردن کم عمق ، اشیاء داخلی فقط ارجاع می شوند ، در حالی که اشیاء بیرونی در یک آدرس حافظه جداگانه کپی می شوند.

از طرف دیگر ، deepcopy() عملکرد copy ماژول شیء را به طور کامل کپی می کند (هر دو اشیاء داخلی و بیرونی در مکان های مختلف حافظه ذخیره می شوند). کد زیر نشان می دهد که چگونه می توانیم اشیاء را در کد خود کپی کنیم:

import copy

categories = {
    'Fruits' : ['Apple', 'Banana', 'Mango'],
    'Flowers' : ['Rose', 'Sunflower', 'Tulip'],
}

# deep copying the dictionary
categories_copy = copy.deepcopy(categories)

print(f"""
Do 'categories' and 'categories_copy' inner object share same memory address? 
--> {id(categories_copy['Fruits']) == id(categories['Fruits'])}
""")

print(f"""
Do 'categories' and 'categories_copy' outer object share same memory address? 
--> {id(categories_copy) == id(categories)}
""")

خروجی:

آیا “دسته بندی ها” و “دسته بندی_کپی” شیء داخلی آدرس حافظه مشابه را به اشتراک می گذارد؟

-> نادرست

آیا “دسته بندی ها” و “دسته بندی_کپی” شیء بیرونی آدرس حافظه مشابه را به اشتراک می گذارند؟

-> نادرست

در کد ، ما فرهنگ لغت را با استفاده از deepcopy() عملکرد. وقتی آدرس حافظه داخلی و اشیاء بیرونی ذخیره شده در هر دو شناسه را مقایسه کردیم ، می بینیم که آنها به طور جداگانه در حافظه ذخیره می شوند.

پیشنهاد می‌کنیم بخوانید:  خواندن و نوشتن فایل‌های JSON با Node.js یکی از بهترین راه‌ها برای تبادل اطلاعات بین برنامه‌های نوشته شده به زبان‌های مختلف، استفاده از فرمت JSON (JavaScript Object Notation) است. به لطف یکنواختی و سادگی، JSON تقریباً به طور کامل جایگزین XML به عنوان فرمت استاندارد تبادل داده در نرم افزار، به ویژه در خدمات وب شده است. با توجه به گستردگی ...

بنابراین بسته به وضعیت ، از یک کپی کم عمق یا یک کپی عمیق استفاده خواهید کرد.

به عنوان مثال ، اگر فقط می خواهید شیء بیرونی را کپی کنید و شیء تو در تو را برای همه یکسان نگه دارید ، باید یک نسخه کم عمق را انتخاب کنید. اگر کلاس را برای ایجاد شناسه دانش آموزان از درجه X تعریف کرده اید ، ممکن است نیاز به حفظ آن داشته باشید self.grade = X برای همه دانش آموزان در چنین مواردی ، شما فقط می توانید به شیء تو در تو مراجعه کنید.

همچنین ، برای اشیاء غیر تو در تو ، روش کپی کم عمق هدف را برآورده می کند ، زیرا هیچ اشیاء تو در تو در تو در تو وجود ندارد و کپی کردن کم عمق ، شیء بیرونی را به طور کامل در یک مکان حافظه متفاوت کپی می کند.

از طرف دیگر ، اگر می خواهید یک کپی کامل و مستقل از شیء داشته باشید ، باید شیء را کپی کنید.

اطلاعات بیشتر در مورد کپی کردن اشیاء در پایتون

شما می توانید از copy ماژول برای هر دو اشیاء تغییر ناپذیر و قابل تغییر. اما برای اشیاء تغییر ناپذیر ، می توانید از اپراتور واگذاری نیز استفاده کنید = برای کپی کردن اشیاء.

اکنون ، همانطور که قبلاً اشاره کردم ، در این حالت نیز هنگام استفاده از این شیء ارجاع می شود = اپراتور اما ، هنگامی که اشیاء غیرقابل تغییر را جهش می دهید ، اشیاء جهش یافته در یک مکان حافظه متفاوت ذخیره می شوند. این باعث می شود نام مستعار شیء اصلی به یک شیء مستقل باشد و به همان آدرس حافظه مانند گذشته اشاره می کند.

بیایید این را با یک مثال درک کنیم:

str1 = "String" # created a string object

str2 = str1 # using '=' to reference the string stored in 'str1'

print(str2, str1, sep='\n') # printing the strings

خروجی:

رشته

رشته

در بالا ، متغیر str2 رشته ذخیره شده در متغیر را ارجاع داد str1بشر اساساً ، str2 وت str1 نقطه در همان آدرس حافظه و str2 فقط یک نام مستعار است str1بشر

اما اگر فراتر برویم و رشته را تغییر دهیم str1، پس str1 شروع به اشاره به یک مکان حافظه جدید می کند (از آنجا که یک رشته تغییر ناپذیر است ، اگر اصلاح شود ، در یک آدرس حافظه متفاوت ذخیره می شود). اما str2 هنوز هم به آدرس حافظه قبلی اشاره خواهد کرد ، که معمولاً هدف از کپی کردن اشیاء را برآورده می کند.

str1 = "String"

str2 = str1

# printing memory addresses of both the variables before mutation.
print(f"""
Memory address of str1: {id(str1)}
Memory address of str2: {id(str2)}
""")

str1+='***' # concatenated the string '***' with str1.

print(str2, str1, sep='\n')

# printing memory addresses of both the variables after mutation.
print(f"""
Memory address of str1: {id(str1)}
Memory address of str2: {id(str2)}
""")

خروجی:

آدرس حافظه STR1: 2652367074480

آدرس حافظه STR2: 2652367074480

رشته

رشته ***

آدرس حافظه Str1: 2652367370736

آدرس حافظه STR2: 2652367074480

یادداشت: آدرس حافظه ممکن است متفاوت باشد روی دستگاه شما از آنهایی که در بالا نشان داده شده است.

اکنون ، در مثال بالا ، ابتدا یک شیء رشته ایجاد کردیم و آن را به متغیر دیگری ارجاع دادیم و آدرس های حافظه هر دو متغیر را چاپ کردیم. سپس رشته اصلی را اصلاح کردیم و دوباره آدرسهای حافظه هر دو متغیر را چاپ کردیم.

در خروجی ، می بینیم که آدرس حافظه هر دو متغیر قبل از جهش یکسان بود. بنابراین می بینید که هر دو متغیر به همان مکان حافظه اشاره می کردند. اما پس از جهش ، متغیر str1 شروع به اشاره به یک مکان حافظه متفاوت ، بدین ترتیب نام مستعار str2 یک شیء مستقل ، که هنوز هم در آدرس حافظه قبلی نشان می دهد.

به طور خلاصه ، می توانید از = اگر قصد دارید آن را بیشتر در برنامه تغییر دهید ، اپراتور برای ذخیره یک کپی از شیء اصلی.

خلاصه

در این آموزش ، شما در مورد کپی کردن اشیاء در پایتون آموخته اید. به طور خاص ، ما در مورد آن صحبت کردیم:

  • چگونه اپراتور واگذاری = برای مراجعه به و کپی نکردن استفاده می شود.

  • داخلی copy ماژول ، که توابعی را فراهم می کند که به ما امکان می دهد کپی کرده و اشیاء را در برنامه خود کپی کرده و کپی کنید.

  • مفهوم کپی کم عمق و کپی عمیق ، که هنگام کپی کردن اشیاء مرکب ضروری هستند.

  • چگونه یک کپی کم عمق شیء بیرونی را کپی می کند و اشیاء داخلی را ارجاع می دهد.

  • چگونه یک کپی عمیق هم از شیء بیرونی و هم اشیاء داخلی کپی می کند.

  • چگونه برای اشیاء تغییر ناپذیر ، اپراتور تکالیف برای کپی کردن اشیاء بیشتر اوقات خوب کار می کند.

با تشکر از خواندن!