copy --- عملیات کپی کم‌عمق و عمیق

کد منبع: Lib/copy.py


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

خلاصه‌ی رابط:

copy.copy(obj)

یک کپی سطحی از obj برمی‌گرداند.

copy.deepcopy(obj[, memo])

یک کپی عمیق از obj برمی‌گرداند.

copy.replace(obj, /, **changes)

شیء جدیدی از همان نوع obj ایجاد می‌کند و فیلدها را با مقادیر changes جایگزین می‌کند.

اضافه شده در نسخه‌ی 3.13.

exception copy.Error

برای خطاهای خاص ماژول پرتاب می‌شود.

تفاوت میان کپی کم‌عمق و کپی عمیق تنها برای اشیاء مرکب (اشیایی که شامل اشیاء دیگر هستند، مانند فهرست‌ها یا نمونه‌های کلاس) اهمیت دارد:

  • یک کپی سطحی یک شیء مرکب جدید می‌سازد و سپس (تا حد امکان) ارجاع‌ها به اشیاء موجود در شیء اصلی را در آن درج می‌کند.

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

دو مشکل اغلب در عملیات کپی عمیق وجود دارد که در عملیات کپی سطحی وجود ندارد:

  • اشیای بازگشتی (اشیای مرکبی که به‌طور مستقیم یا غیرمستقیم شامل ارجاعی به خود هستند) ممکن است باعث ایجاد یک حلقه بازگشتی شوند.

  • از آنجا که کپی عمیق همه‌چیز را کپی می‌کند، ممکن است بیش از حد کپی کند، مانند داده‌هایی که قرار است بین کپی‌ها به اشتراک گذاشته شوند.

تابع deepcopy() با انجام موارد زیر از این مشکلات اجتناب می‌کند:

  • نگه‌داری یک دیکشنری memo از اشیایی که در طول گذر کپی جاری پیش‌تر کپی شده‌اند؛ و

  • به کلاس‌های تعریف‌شده توسط کاربر اجازه می‌دهد تا عملیات کپی یا مجموعه‌ی کامپوننت‌های کپی‌شده را بازنویسی کنند.

این ماژول انواعی مانند ماژول، متد، ردگیری پشته، فریم پشته، پرونده، سوکت، پنجره یا هر نوع مشابه را کپی نمی‌کند. این ماژول توابع و کلاس‌ها را (به‌صورت سطحی و عمیق) با بازگرداندن شیء اصلی بدون تغییر «کپی» می‌کند؛ این رفتار با نحوه‌ی برخورد ماژول pickle با این موارد سازگار است.

می‌توان کپی‌های سطحی بسیاری از مجموعه‌ها را با استفاده از متد copy() متناظر (مانند list.copy()، dict.copy() یا set.copy())، و کپی‌های سطحی دنباله‌ها (مانند فهرست‌ها یا bytearrayها) را با ایجاد اسلایسی از کل دنباله (sequence[:]) ساخت. با این حال، این متدها و اسلایس‌کردن ممکن است هنگام کپی کردن نمونه‌ای از یک زیرکلاس، نمونه‌ای از نوع پایه را ایجاد کنند، در حالی که copy.copy() معمولاً نمونه‌ای از همان نوع را برمی‌گرداند.

کلاس‌ها می‌توانند برای کنترل کپی‌سازی از همان رابط‌هایی استفاده کنند که برای کنترل پیکل‌کردن استفاده می‌کنند. برای آگاهی از این متدها، توضیحات ماژول pickle را ببینید. در واقع، ماژول copy از توابع پیکل ثبت‌شده در ماژول copyreg استفاده می‌کند.

برای اینکه یک کلاس بتواند پیاده‌سازی کپی خود را تعریف کند، می‌تواند متدهای ویژه‌ی __copy__() و __deepcopy__() را تعریف کند.

object.__copy__(self)

برای پیاده‌سازی عملیات کپی کم‌عمق فراخوانی می‌شود؛ آرگومان اضافه‌ای ارسال نمی‌شود.

object.__deepcopy__(self, memo)

برای پیاده‌سازی عملیات کپی عمیق فراخوانی می‌شود؛ یک آرگومان به آن داده می‌شود، دیکشنری memo. اگر پیاده‌سازی __deepcopy__ نیاز داشته باشد یک کپی عمیق از یک کامپوننت ایجاد کند، باید تابع deepcopy() را با آن کامپوننت به‌عنوان آرگومان اول و دیکشنری memo به‌عنوان آرگومان دوم فراخوانی کند. با دیکشنری memo باید به‌عنوان یک شیء غیرشفاف رفتار شود.

تابع copy.replace() محدودتر از copy() و deepcopy() است و فقط از تاپل‌های نام‌دار ایجادشده توسط namedtuple()، dataclasses و سایر کلاس‌هایی که متد __replace__() را تعریف می‌کنند، پشتیبانی می‌کند.

object.__replace__(self, /, **changes)

این متد باید یک شیء جدید از همان نوع ایجاد کند و فیلدها را با مقادیر changes جایگزین کند.

اضافه شده در نسخه‌ی 3.13.

همچنین ملاحظه نمائید

ماژول pickle

بحثی درباره‌ی متدهای ویژه‌ای که برای پشتیبانی از بازیابی و بازگردانی وضعیت شیء به کار می‌روند.