خانه / آموزش‌ها / تفاوت is و == در پایتون (Identity vs Equality)

تفاوت is و == در پایتون (Identity vs Equality)

🐍 HomeOfPython
|
📅 1404/10/22

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

در پایتون دو روش اصلی برای مقایسه متغیرها وجود دارد: علامت == (Equality) و کلمه کلیدی is (Identity). درک تفاوت این دو برای جلوگیری از باگ‌های منطقی در برنامه بسیار حیاتی است.

مفهوم برابری مقدار (Equality - ==)

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

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

در این مثال می‌بینیم که چون مقدارها یکسان هستند، نتیجه True است.

Python

مثال دوم: مقایسه لیست‌ها

حتی اگر دو لیست جداگانه بسازیم، اگر محتویات آن‌ها یکی باشد، == مقدار True برمی‌گرداند.

Python

مفهوم هویت و یکسانی شیء (Identity - is)

عملگر is بررسی می‌کند که آیا دو متغیر دقیقاً به یک جایگاه در حافظه (یک شیء واحد) اشاره می‌کنند یا خیر. به عبارتی is بررسی می‌کند که آیا این دو متغیر، نام‌های مختلفی برای یک موجودیت هستند؟

تفاوت حافظه در is و ==

مثال اول: لیست‌های مستقل

در اینجا، با اینکه محتوا یکسان است، اما چون دو لیست جداگانه در حافظه ساخته شده‌اند، is مقدار False می‌دهد.

Python

مثال دوم: ارجاع مشترک (Aliasing)

اگر یک متغیر را برابر متغیر دیگر قرار دهیم، هر دو به یک خانه حافظه اشاره می‌کنند.

Python

مثال سوم: استفاده از Not is

برای بررسی اینکه دو شیء یکی نیستند از is not استفاده می‌کنیم.

python
# Example 3: Syntax Usage
x = [1]
y = [2]

if x is not y:
    print("They are different objects")

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

در این سطح به عمق مدیریت حافظه در پایتون، تابع id() و مفاهیم بهینه‌سازی مفسر CPython مثل Interning می‌پردازیم.

تابع id() و آدرس حافظه

در CPython، تابع id() آدرس حافظه شیء را برمی‌گرداند. عملگر is در واقع معادل کد زیر عمل می‌کند: id(a) == id(b)

مثال فنی: بررسی آدرس‌ها

Python

مفهوم Integer Interning (کش اعداد صحیح کوچک)

پایتون برای بهینه‌سازی سرعت، اعداد صحیح کوچک (معمولاً بین 5- تا 256) را در شروع برنامه در حافظه کش (Pre-allocate) می‌کند. بنابراین اگر دو متغیر را برابر 100 قرار دهید، هر دو به یک شیء از پیش ساخته شده اشاره می‌کنند. اما برای اعداد بزرگ، هر بار شیء جدیدی ساخته می‌شود.

نکته: مفسرهای مختلف یا حتی اجرا در IDEهای مختلف ممکن است رفتارهای متفاوتی در بهینه‌سازی (Compiler Optimization) نشان دهند، اما در شل استاندارد پایتون قانون زیر صادق است.

Python

مفهوم String Interning

پایتون رشته‌های کوتاه که شبیه شناسه (Identifier) هستند (فقط حروف، اعداد و زیرخط) را گاهی اوقات Intern می‌کند تا حافظه کمتری مصرف شود. اما نباید روی این رفتار برای مقایسه منطقی حساب باز کرد.

Python

بهترین روش مقایسه با None (Best Practice)

طبق استاندارد PEP 8، برای مقایسه با None همیشه باید از is یا is not استفاده کنید، نه ==. دلیل این امر این است که None یک Singleton در پایتون است (فقط یک نمونه از آن در حافظه وجود دارد) و همچنین کلاس‌های سفارشی ممکن است رفتار == را تغییر داده باشند اما is قابل تغییر نیست.

python
# Static: Correct Pattern (PEP 8)
value = None

# غلط
if value == None:
    pass

# صحیح
if value is None:
    pass

تغییر رفتار Equality در کلاس‌ها

ما می‌توانیم با متد جادویی __eq__ رفتار == را تغییر دهیم، اما رفتار is هرگز قابل تغییر نیست.

Python