আমি এই প্রশ্নের পাইথন 3 এর জন্য একটি আপডেট উত্তর লিখছি।
__eq__
পাইথনে কীভাবে পরিচালনা করা হয় এবং কোন ক্রমে?
a == b
এটি সাধারণত বোঝা যায়, তবে সবসময় তা হয় না, যা a == b
ডাকে a.__eq__(b)
বা type(a).__eq__(a, b)
।
স্পষ্টতই, মূল্যায়নের ক্রমটি হ'ল:
b
এর ধরণ যদি ধরণের ধরণের কঠোর সাবক্লাস হয় (একই ধরণের নয়) a
এবং এর একটি __eq__
থাকে তবে তা কল করুন এবং তুলনাটি কার্যকর হলে মানটি ফিরিয়ে দিন,
- অন্যথায়, যদি
a
এটি থাকে __eq__
, কল করুন এবং যদি তুলনাটি বাস্তবায়িত হয় তবে তা ফিরিয়ে দিন,
- অন্যথায় দেখুন, আমরা বি'কে কল করি নি
__eq__
এবং এটি রয়েছে, তারপরে কল করুন এবং তুলনা কার্যকর হলে এটি ফিরিয়ে দিন,
- অন্যথায়, অবশেষে, পরিচয়ের জন্য তুলনা করুন, একই তুলনা করুন
is
।
পদ্ধতিটি ফিরে আসে যদি আমরা কোনও তুলনা কার্যকর না করা হয় তা জানি NotImplemented
।
(পাইথন 2 এ, এমন একটি __cmp__
পদ্ধতি ছিল যা সন্ধান করা হয়েছিল, তবে এটি পাইথন 3 এ অবহেলা ও অপসারণ করা হয়েছিল)
আসুন বি সাবক্লাস এ দিয়ে নিজের জন্য প্রথম চেকের আচরণটি পরীক্ষা করি, যা দেখায় যে গৃহীত উত্তরটি এই গণনায় ভুল:
class A:
value = 3
def __eq__(self, other):
print('A __eq__ called')
return self.value == other.value
class B(A):
value = 4
def __eq__(self, other):
print('B __eq__ called')
return self.value == other.value
a, b = A(), B()
a == b
যা B __eq__ called
ফিরে আসার আগে কেবল মুদ্রণ করে False
।
আমরা কীভাবে এই সম্পূর্ণ অ্যালগরিদম জানি?
এখানে অন্যান্য উত্তরগুলি অসম্পূর্ণ এবং পুরানো বলে মনে হচ্ছে, তাই আমি তথ্য আপডেট করতে যাচ্ছি এবং কীভাবে আপনি নিজের জন্য এটি দেখতে পারেন তা আপনাকে দেখাব।
এটি সি স্তরে পরিচালনা করা হয়।
আমাদের এখানে দুটি ভিন্ন বিটের কোড দেখতে হবে - __eq__
শ্রেণীর অবজেক্টের জন্য ডিফল্ট object
, এবং কোডটি যেটি দেখায় এবং __eq__
পদ্ধতিটি এটি ডিফল্ট __eq__
বা কাস্টম ব্যবহার করে তা নির্বিশেষে কল করে ।
ডিফল্ট __eq__
প্রাসঙ্গিক সি এপিআই ডক্সে সন্ধান __eq__
করা আমাদের দেখায় যে এটি দ্বারা পরিচালিত হয় - যা টাইপ সংজ্ঞায়িতটির জন্য সংজ্ঞায়িত হয় ।__eq__
tp_richcompare
"object"
cpython/Objects/typeobject.c
object_richcompare
case Py_EQ:
case Py_EQ:
/* Return NotImplemented instead of False, so if two
objects are compared, both get a chance at the
comparison. See issue
res = (self == other) ? Py_True : Py_NotImplemented;
Py_INCREF(res);
break;
সুতরাং এখানে, যদি self == other
আমরা ফিরে True
, অন্যথায় আমরা NotImplemented
বস্তু ফিরে । এটি কোনও অবজেক্টের সাবক্লাসের জন্য ডিফল্ট আচরণ যা তার নিজস্ব __eq__
পদ্ধতি প্রয়োগ করে না ।
কিভাবে __eq__
ডাকা হয়
তারপরে আমরা সিআই এপি ডক্স পাই পাইবজেক্ট_রিচকম্পের ফাংশনটি পাই যা কল করে do_richcompare
।
তারপরে আমরা দেখতে পেলাম যে সি সংজ্ঞার tp_richcompare
জন্য তৈরি ফাংশনটি "object"
ডেকে আনে do_richcompare
, সুতরাং আসুন আমরা এটি আরও ঘনিষ্ঠভাবে দেখি।
এই ফাংশনটির প্রথম চেকটি বস্তুর তুলনা করার শর্তের জন্য:
- হয় না একই ধরনের, কিন্তু
- দ্বিতীয় প্রকারটি প্রথম ধরণের একটি উপশ্রেণী, এবং
- দ্বিতীয় ধরণের একটি
__eq__
পদ্ধতি আছে,
তারপরে অন্যটির পদ্ধতিটি কল করে আর্গুমেন্টগুলি অদলবদল করে, প্রয়োগ করা হলে মানটি ফিরিয়ে দেয়। যদি সেই পদ্ধতিটি প্রয়োগ না করা হয়, তবে আমরা চালিয়ে যা ...
if (!Py_IS_TYPE(v, Py_TYPE(w)) &&
PyType_IsSubtype(Py_TYPE(w), Py_TYPE(v)) &&
(f = Py_TYPE(w)->tp_richcompare) != NULL) {
checked_reverse_op = 1;
res = (*f)(w, v, _Py_SwappedOp[op]);
if (res != Py_NotImplemented)
return res;
Py_DECREF(res);
পরবর্তী আমরা দেখতে পাই যে আমরা __eq__
প্রথম ধরণটি থেকে পদ্ধতিটি অনুসন্ধান করতে পারি এবং এটি কল করতে পারি। যতক্ষণ না ফলাফলটি NotImplemented হয় না, অর্থাৎ এটি কার্যকর করা হয়, আমরা এটি ফিরিয়ে দিই।
if ((f = Py_TYPE(v)->tp_richcompare) != NULL) {
res = (*f)(v, w, op);
if (res != Py_NotImplemented)
return res;
Py_DECREF(res);
অন্যথায় যদি আমরা অন্য ধরণের পদ্ধতিটি চেষ্টা না করে এবং এটি সেখানে থাকে তবে আমরা তারপরে চেষ্টা করে থাকি এবং যদি তুলনাটি বাস্তবায়িত হয় তবে আমরা এটিকে ফিরিয়ে দিই।
if (!checked_reverse_op && (f = Py_TYPE(w)->tp_richcompare) != NULL) {
res = (*f)(w, v, _Py_SwappedOp[op]);
if (res != Py_NotImplemented)
return res;
Py_DECREF(res);
}
শেষ অবধি, কারওর জন্য এটি প্রয়োগ না করা হলে আমরা ফ্যালব্যাক পাই।
ফলব্যাকটি বস্তুর সনাক্তকরণের জন্য যাচাই করে, এটি মেমরির একই জায়গায় একই জিনিস কিনা - এটি একই পরীক্ষার জন্য self is other
:
/* If neither object implements it, provide a sensible default
for == and !=, but raise an exception for ordering. */
switch (op) {
case Py_EQ:
res = (v == w) ? Py_True : Py_False;
break;
উপসংহার
তুলনায় আমরা প্রথমে তুলনার সাবক্লাস বাস্তবায়নকে সম্মান করি।
তারপরে আমরা প্রথম অবজেক্টের প্রয়োগের সাথে তুলনা করার চেষ্টা করি, তারপরে দ্বিতীয়টিকে যদি এটি না বলা হয় with
সমাপ্তির জন্য তুলনার জন্য অবশেষে আমরা পরিচয়ের জন্য একটি পরীক্ষা ব্যবহার করি।