وبلاگ رسانگار
با ما حرفه ای باشید

سرور مجازی NVMe

‘is’ در مقابل ‘==’ در پایتون – مقایسه شی

0 6
زمان لازم برای مطالعه: 5 دقیقه


‘is’ در مقابل ‘==’ در پایتون

پایتون دو عملگر بسیار مشابه برای بررسی برابری دو شیء دارد. این دو اپراتور هستند is و ==.

آنها معمولاً با یکدیگر اشتباه گرفته می شوند زیرا با انواع داده های ساده مانند intشن strings (که بسیاری از افراد با آن شروع به یادگیری پایتون می کنند) به نظر می رسد همان کار را انجام می دهند:

x = 5
s = "example"

print("x == 5: " + str(x == 5))
print("x is 5: " + str(x is 5))
print("s == 'example': " + str(s == "example"))
print("s is 'example': " + str(s is "example"))

اجرای این کد منجر به موارد زیر می شود:

x == 5: True
x is 5: True
s == 'example': True
s is 'example': True

این نشان می دهد که == و is همان مقدار را برگردانید (True) در این موارد. با این حال، اگر سعی کردید این کار را با ساختار پیچیده تری انجام دهید:

some_list = (1)

print("some_list == (1): " + str(some_list == (1)))
print("some_list is (1): " + str(some_list is (1)))

این منجر به:

some_list == (1): True
some_list is (1): False

در اینجا مشخص می شود که این عملگرها یکسان نیستند.

تفاوت از این واقعیت ناشی می شود که is بررسی می کند هویت (اشیاء)، در حالی که == بررسی می کند برابری (ارزش).

در اینجا مثال دیگری وجود دارد که ممکن است تفاوت بین این دو عملگر را روشن کند:

some_list1 = (1)
some_list2 = (1)
some_list3 = some_list1

print("some_list1 == some_list2: " + str(some_list1 == some_list2))
print("some_list1 is some_list2: " + str(some_list1 is some_list2))
print("some_list1 == some_list3: " + str(some_list1 == some_list3))
print("some_list1 is some_list3: " + str(some_list1 is some_list3))

این منجر به:

some_list1 == some_list2: True
some_list1 is some_list2: False
some_list1 == some_list3: True
some_list1 is some_list3: True

همان طور که ما می توانیم ببینیم، some_list1 است برابر به some_list2 از نظر مقدار (هر دو برابر هستند (1)))، اما نیستند همسان، به این معنی که آنها یک شی نیستند، حتی اگر مقادیر مساوی داشته باشند.

با این حال، some_list1 هر دو برابر و همسان به some_list3 از آنجایی که آنها به همان شی در حافظه ارجاع می دهند.

انواع داده های قابل تغییر در مقابل غیرقابل تغییر

در حالی که این بخش از مشکل اکنون ممکن است واضح باشد (زمانی که متغیرها را نامگذاری کرده ایم)، ممکن است یک سوال دیگر ظاهر شود:

چطور is و == رفتاری مشابه با بی نام داشته باشید int و string مقادیر (مانند 5 و "example") اما با لیست های بدون نام یکسان رفتار نکنید (مانند (1)

دو نوع داده در پایتون وجود دارد – قابل تغییر و تغییرناپذیر.

  • انواع داده های قابل تغییر، انواع داده هایی هستند که می توانید در طول زمان آنها را تغییر دهید
  • انواع داده های تغییرناپذیر ثابت می مانند (محل حافظه یکسانی دارند، یعنی همان is چک ها) پس از ایجاد آنها
پیشنهاد می‌کنیم بخوانید:  زیرخط ها را با Spaces در پایتون جایگزین کنید

انواع داده های قابل تغییر عبارتند از: list، dictionary، setو کلاس های تعریف شده توسط کاربر.

انواع داده های تغییرناپذیر عبارتند از: int، float، decimal، bool، string، tuple، و range.

مانند بسیاری از زبان‌های دیگر، پایتون با انواع داده‌های غیرقابل تغییر متفاوت از انواع قابل تغییر مدیریت می‌کند، یعنی فقط یک بار آنها را در حافظه ذخیره می‌کند.

بنابراین هر 5 شما در کد خود استفاده می کنید دقیقاً یکسان است 5 شما در جاهای دیگر در کد خود استفاده می کنید، و همین امر در مورد حروف رشته ای که استفاده می کنید نیز صدق می کند.

اگر از رشته استفاده می کنید "example" یک بار، هر بار دیگری که استفاده می کنید "example" دقیقاً همان شیء خواهد بود. این را ببینید توجه داشته باشید برای توضیح بیشتر

ما از یک تابع پایتون به نام استفاده خواهیم کرد id() که یک شناسه منحصر به فرد برای هر شی چاپ می کند تا نگاهی دقیق تر به مفهوم تغییرپذیری در عمل داشته باشد:

s = "example"
print("Id of s: " + str(id(s)))
print("Id of the String 'example': " + str(id("example")) + " (note that it's the same as the variable s)")
print("s is 'example': " + str(s is "example"))

print("Change s to something else, then back to 'example'.")
s = "something else"
s = "example"
print("Id of s: " + str(id(s)))
print("s is 'example': " + str(s is "example"))
print()

list1 = (1)
list2 = list1
print("Id of list1: " + str(id(list1)))
print("Id of list2: " + str(id(list2)))
print("Id of (1): " + str(id((1))) + " (note that it's not the same as list1!)")
print("list1 == list2: " + str(list1 == list2))
print("list1 is list2: " + str(list1 is list2))

print("Change list1 to something else, then back to the original ((1)) value.")
list1 = (2)
list1 = (1)
print("Id of list1: " + str(id(list1)))
print("list1 == list2: " + str(list1 == list2))
print("list1 is list2: " + str(list1 is list2))

این خروجی:

Id of s: 22531456
Id of the String 'example': 22531456 (note that it's the same as the variable s)
s is 'example': True
Change s to something else, then back to 'example'.
Id of s: 22531456
s is 'example': True

Id of list1: 22103504
Id of list2: 22103504
Id of (1): 22104664 (note that it's not the same as list1!)
list1 == list2: True
list1 is list2: True
Change list1 to something else, then back to the original ((1)) value.
Id of list1: 22591368
list1 == list2: True
list1 is list2: False

می بینیم که در قسمت اول مثال، s دقیقا به همان حالت برگشت "example" شیئی که در ابتدا به آن اختصاص داده شده بود، حتی اگر مقدار آن را تغییر دهیم s در عین حال.

با این حال، list همان شیئی که مقدار آن است را بر نمی گرداند (1)، اما یک شی کاملاً جدید ایجاد می شود، حتی اگر همان را داشته باشد ارزش به عنوان اولین (1).

اگر کد بالا را اجرا کنید، احتمالاً شناسه های مختلفی برای اشیاء دریافت خواهید کرد، اما برابری ها یکسان خواهند بود.

پیشنهاد می‌کنیم بخوانید:  کوروتین ها در پایتون

چه زمانی “is” و “==” به ترتیب استفاده می شود؟

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

بعلاوه، is به طور کلی سریعتر از == عملگر زیرا به سادگی برابری عدد صحیح آدرس حافظه را بررسی می کند.

یادداشت مهم: تنها موقعیت زمانی که is دقیقاً همانطور که انتظار می رود با کلاس ها/اشیاء تک تن (مانند None). حتی با اشیاء تغییرناپذیر، موقعیت هایی وجود دارد که در آن is میکند نه همانطور که انتظار می رود کار کنید

به عنوان مثال، برای بزرگ string اشیاء تولید شده توسط برخی منطق کد، یا بزرگ intاس، is می تواند (و خواهد) رفتار غیر قابل پیش بینی داشته باشد. مگر اینکه شما از طریق تلاش از کارآموزی (یعنی کاملاً مطمئن شوید که فقط یک کپی از a string/int/و غیره. وجود دارد)، تمام اشیاء تغییرناپذیر مختلفی که قصد استفاده از آنها را دارید، is غیر قابل پیش بینی خواهد بود

نکته اصلی این است: استفاده کنید == در 99 درصد موارد

اگر دو شی هستند همسان آنها نیز هستند برابرو لزوماً برعکس آن صادق نیست.

نادیده گرفتن اپراتورهای ‘==’ و ‘!=’

اپراتورها != و is not مانند همتایان “مثبت” خود رفتار می کنند. برای مثال، != برمی گرداند True اگر اشیا ارزش یکسانی نداشته باشند، در حالی که is not برمی گرداند True اگر اشیاء در یک آدرس حافظه ذخیره نشده باشند.

یکی دیگر از تفاوت های این دو عملگر این است که می توانید رفتار آنها را نادیده بگیرید ==/!= برای یک کلاس سفارشی، در حالی که شما نمی تواند نادیده گرفتن رفتار is.

اگر سفارشی را پیاده سازی کنید __eq()__ روش در کلاس خود، شما می توانید تغییر دهید که چگونه ==/!= اپراتورها رفتار می کنند:

class TestingEQ:
    def __init__(self, n):
        self.n = n

    
    
    def __eq__(self, other):
        if (self.n % 2 == 0 and other % 2 == 0):
            return True
        else:
            return False


print(5 == TestingEQ(1))
print(2 == TestingEQ(10))
print(1 != TestingEQ(2))

این منجر به:

False
True
True

نتیجه

به اختصار، ==/!= بررسی می کند برابری (بر اساس ارزش) و is/is not بررسی می کند که آیا دو شی هستند همسان، یعنی آدرس حافظه آنها را بررسی می کند.

با این حال، از استفاده خودداری کنید is مگر اینکه دقیقاً بدانید که دارید چه می‌کنید، یا زمانی که با اشیاء تک‌تنه سروکار دارید None، زیرا می تواند غیرقابل پیش بینی رفتار کند.

(برچسب‌ها به ترجمه)# python



منتشر شده در 1403-01-16 23:44:11

امتیاز شما به این مطلب
دیدگاه شما در خصوص مطلب چیست ؟

آدرس ایمیل شما منتشر نخواهد شد.

لطفا دیدگاه خود را با احترام به دیدگاه های دیگران و با توجه به محتوای مطلب درج کنید