خانه / آموزش‌ها / کپی سطحی و عمیق در پایتون (Shallow vs Deep Copy)

کپی سطحی و عمیق در پایتون (Shallow vs Deep Copy)

🐍 HomeOfPython
|
📅 1404/10/20

سطح مقدماتی (Beginner Level)

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

۱. انتساب در برابر کپی (Assignment vs Copy)

وقتی یک لیست یا دیکشنری را با علامت = به متغیر دیگری اختصاص می‌دهید، شما داده را کپی نمی‌کنید؛ بلکه فقط یک برچسب (Reference) جدید به همان مکان در حافظه می‌زنید. تغییر در یکی، باعث تغییر در دیگری می‌شود.

مثال ۱: رفتار پیش‌فرض انتساب (بدون کپی)

Python

مثال ۲: بررسی شناسه حافظه (id) با استفاده از تابع id() می‌توانیم ببینیم که هر دو متغیر دقیقاً یک شیء هستند.

Python

۲. کپی سطحی (Shallow Copy)

برای اینکه تغییرات روی متغیر جدید، متغیر اصلی را خراب نکند، باید از کپی استفاده کنیم. ساده‌ترین روش، کپی سطحی است. در لیست‌ها می‌توانیم از متد .copy() یا اسلایسینگ [:] استفاده کنیم.

مثال ۱: استفاده از متد copy

Python

مثال ۲: استفاده از Slicing (روش پایتونی)

Python

مثال ۳: کپی در دیکشنری‌ها

python
# Example 3: Static snippet for dict (works same as list)
data = {"name": "Ali", "age": 25}
data_copy = data.copy()

سطح پیشرفته (Professional Level)

زمانی که با اشیاء تو در تو (Nested Objects) کار می‌کنیم (مثلاً لیستی که داخلش لیست دیگری دارد)، کپی سطحی دیگر امن نیست. در اینجا باید تفاوت دقیق نحوه مدیریت حافظه در Shallow Copy و Deep Copy را درک کنیم.

۱. مشکل کپی سطحی در داده‌های تو در تو

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

دیاگرام کپی سطحی

مثال ۱: شکست کپی سطحی

Python

۲. کپی عمیق (Deep Copy)

برای حل این مشکل، ماژول استاندارد copy و تابع deepcopy را داریم. این تابع به صورت بازگشتی تمام اشیاء داخلی را پیدا کرده و کپی می‌کند.

مثال ۱: استفاده از copy.deepcopy

Python

مثال ۲: مقایسه عملکرد روی دیکشنری‌های تو در تو

Python

۳. نکات فنی و پرفورمنس

  • هزینه: deepcopy بسیار کندتر از copy سطحی است زیرا باید کل درخت اشیاء را پیمایش کند. اگر داده‌های تو در تو ندارید، هرگز از deepcopy استفاده نکنید.
  • اشیاء تغییرناپذیر (Immutable): کپی کردن (چه سطحی چه عمیق) روی اشیاء تغییرناپذیر مثل Tuple یا String معمولاً کپی جدید ایجاد نمی‌کند و پایتون برای بهینه‌سازی همان ارجاع قبلی را برمی‌گرداند.

مثال: بهینه‌سازی در تاپل‌ها

Python

۴. شخصی‌سازی کپی با Magic Methods

شما می‌توانید نحوه کپی شدن کلاس‌های خود را با متدهای __copy__ و __deepcopy__ کنترل کنید.

python
# Static Example: Customizing copy behavior
import copy

class MyData:
    def __init__(self, data):
        self.data = data
    
    def __copy__(self):
        # منطق دلخواه برای کپی سطحی
        print("Custom shallow copy triggered")
        return MyData(self.data)

    def __deepcopy__(self, memo):
        # منطق دلخواه برای کپی عمیق
        print("Custom deep copy triggered")
        return MyData(copy.deepcopy(self.data, memo))