পাইথনে আমি __ne__ পদক্ষেপে______ প্রয়োগ করতে পারি?


101

আমার একটি ক্লাস রয়েছে যেখানে আমি __eq__পদ্ধতিটি ওভাররাইড করতে চাই । এটি বোধ করার মতো বলে মনে হচ্ছে যে আমারও সেই __ne__পদ্ধতিটি ওভাররাইড করা উচিত , তবে এটি কি এরূপ হিসাবে প্রয়োগ __ne__করা অর্থবোধ করে __eq__?

class A:

    def __init__(self, attr):
        self.attr = attr

    def __eq__(self, other):
        return self.attr == other.attr
    
    def __ne__(self, other):
        return not self.__eq__(other)

বা পাইথন যেভাবে এই পদ্ধতিগুলি ব্যবহার করে যা এটি একটি ভাল ধারণা নয় সেটির সাথে আমি কী অনুভব করছি?

উত্তর:


60

হ্যাঁ, এটি পুরোপুরি ঠিক আছে। আসলে, ডকুমেন্টেশন আপনাকে সংজ্ঞায়িত করার __ne__সময় আপনাকে সংজ্ঞায়িত করার জন্য অনুরোধ করে __eq__:

তুলনা অপারেটরদের মধ্যে কোনও অন্তর্নিহিত সম্পর্ক নেই। এর সত্যটি মিথ্যা x==yবলে বোঝায় না x!=y। তদনুসারে, সংজ্ঞা দেওয়ার সময় __eq__(), একটিও নির্ধারণ করা উচিত __ne__()যাতে অপারেটররা প্রত্যাশা অনুযায়ী আচরণ করবে।

অনেক ক্ষেত্রে (যেমন এটির মতো) এটি ফলাফলটিকে অবহেলা করার মতো সহজ __eq__, তবে সর্বদা নয়।


12
এই সঠিক উত্তর (এখানে নিচে, দ্বারা @ হারুন-হল) হয়। আপনার উদ্ধৃত ডকুমেন্টেশন আপনাকে ব্যবহার করে বাস্তবায়ন করতে উত্সাহিত করে না , কেবলমাত্র আপনি এটি প্রয়োগ করেছেন। __ne____eq__
গিয়ারাড

4
@ গুয়ারাড: আসলে সঠিকভাবে দায়িত্ব না দেওয়ার জন্য হারুনের উত্তরটি এখনও কিছুটা ভুল wrong NotImplementedঅপর পক্ষের প্রতিনিধি প্রেরণা হিসাবে এক দিক থেকে প্রত্যাবর্তনকে চিকিত্সা করার পরিবর্তে, (অপারেন্ডকে অন্য অপারেন্ডের সাথে কীভাবে তুলনা করা জানে না তা ধরে নেওয়া) __ne__অপর পক্ষ থেকে স্পষ্টত অর্পণ করা , তারপরে এটি উল্টানো। অদ্ভুত প্রকারের জন্য যেমন, এসকিউএলএলকেমি ওআরএম এর ক্ষেত্রগুলির জন্য এটি সমস্যার সৃষ্টি করেnot self == other__eq____eq__
শ্যাডোর্যাঞ্জার

4
শ্যাডোএ্যাঞ্জারের সমালোচনা কেবল খুব প্যাথলজিকাল কেস (আইএমএইচও) এর ক্ষেত্রে প্রযোজ্য এবং নীচে আমার উত্তরটিতে পুরোপুরি সম্বোধন করা হয়েছে।
অ্যারন হল

4
নতুন ডকুমেন্টেশনগুলি (কমপক্ষে 3.7 এর জন্য, এমনকি আরও আগেও হতে পারে) __ne__স্বয়ংক্রিয়ভাবে প্রতিনিধি হয়ে থাকে __eq__এবং এই উত্তরের উদ্ধৃতিটি ডক্সে আর বিদ্যমান নেই। নীচের লাইনটি কেবলমাত্র বাস্তবায়ন করতে __eq__এবং __ne__ডেলিগেট দেওয়ার জন্য এটি পুরোপুরি পাইথোনিক ।
bluesummers

136

পাইথন, আমার __ne__()উপর নির্ভর করে অপারেটরটি প্রয়োগ করা উচিত __eq__?

সংক্ষিপ্ত উত্তর: এটি বাস্তবায়ন করবেন না, তবে আপনাকে অবশ্যই ব্যবহার করুন ==, না__eq__

পাইথন 3-এ, ডিফল্টরূপে !=অবহেলা করা ==হয়, সুতরাং আপনার এমনকি একটি __ne__লেখারও প্রয়োজন হয় না এবং ডকুমেন্টেশন আর লেখার পক্ষে মতামত দেয় না।

সাধারণভাবে বলতে গেলে পাইথন 3-কেবল কোডের জন্য, পিতা-মাতার বাস্তবায়নকে যেমন ছড়িয়ে দেওয়া দরকার না, যেমন বিল্টিন অবজেক্টের জন্য write

এটি হ'ল রেমন্ড হেটেঙ্গারের মন্তব্যটি মনে রাখবেন :

__ne__পদ্ধতি থেকে স্বয়ংক্রিয়ভাবে অনুসরণ __eq__যদি শুধু __ne__ইতিমধ্যে একটি সুপারক্লাস সংজ্ঞায়িত করা হয় না। সুতরাং, যদি আপনি কোনও বিল্টিন থেকে উত্তরাধিকার সূত্রে পান তবে উভয়কেই ওভাররাইড করা ভাল।

পাইথন 2 এ কাজ করার জন্য যদি আপনার কোডের প্রয়োজন হয় তবে পাইথন 2 এর জন্য প্রস্তাবটি অনুসরণ করুন এবং এটি পাইথন 3 এ কাজ করবে।

পাইথন 2, পাইথন নিজেই স্বয়ংক্রিয়ভাবে অন্য পরিপ্রেক্ষিতে কোনো অপারেশন বাস্তবায়ন না - তাই আপনি সংজ্ঞায়িত করা উচিত __ne__পরিপ্রেক্ষিতে ==পরিবর্তে __eq__। ইজি

class A(object):
    def __eq__(self, other):
        return self.value == other.value

    def __ne__(self, other):
        return not self == other # NOT `return not self.__eq__(other)`

প্রমাণ দেখুন

  • __ne__()উপর ভিত্তি করে বাস্তবায়নকারী অপারেটর __eq__এবং
  • __ne__পাইথন 2 এ মোটেই বাস্তবায়ন করা হচ্ছে না

নীচের প্রদর্শনীতে ভুল আচরণ সরবরাহ করে।

দীর্ঘ উত্তর

ডকুমেন্টেশন পাইথন 2 জন্য বলেছেন:

তুলনা অপারেটরদের মধ্যে কোনও অন্তর্নিহিত সম্পর্ক নেই। এর সত্যটি মিথ্যা x==yবলে বোঝায় না x!=y। তদনুসারে, সংজ্ঞা দেওয়ার সময় __eq__(), একটিও নির্ধারণ করা উচিত __ne__()যাতে অপারেটররা প্রত্যাশা অনুযায়ী আচরণ করবে।

সুতরাং এর অর্থ হ'ল আমরা যদি __ne__উল্টো দিকের দিক দিয়ে সংজ্ঞায়িত করি তবে আমরা __eq__ধারাবাহিক আচরণ পেতে পারি।

ডকুমেন্টেশনের এই বিভাগটি পাইথন 3 এর জন্য আপডেট করা হয়েছে :

ডিফল্টরূপে, __ne__()প্রতিনিধিরা __eq__()ফলাফলটি না করে উল্টে দেয় NotImplemented

এবং "নতুন কী" বিভাগে আমরা দেখি যে এই আচরণটি পরিবর্তিত হয়েছে:

  • !===যদি না ==ফেরায় তবে এখন এর বিপরীতে ফিরে আসে NotImplemented

বাস্তবায়নের জন্য __ne__, আমরা==__eq__ সরাসরি পদ্ধতিটি ব্যবহার না করে অপারেটরটি ব্যবহার করতে পছন্দ করি যাতে self.__eq__(other)কোনও সাবক্লাস যদি NotImplementedপরীক্ষিত প্রকারের জন্য ফিরে আসে , পাইথন other.__eq__(self) ডকুমেন্টেশন থেকে যথাযথভাবে পরীক্ষা করবে :

NotImplementedউদ্দেশ্য

এই ধরণের একক মান রয়েছে। এই মান সহ একটি একক অবজেক্ট আছে। এই অবজেক্টটি বিল্ট-ইন নামের মাধ্যমে অ্যাক্সেস করা হয়েছে NotImplemented। সংখ্যার পদ্ধতি এবং সমৃদ্ধ তুলনা পদ্ধতিগুলি যদি প্রদত্ত অপারেন্ডগুলির জন্য ক্রিয়াকলাপ বাস্তবায়ন না করে তবে এই মানটি ফিরিয়ে দিতে পারে। (দোভাষী তারপরে অপারেটরের উপর নির্ভর করে প্রতিফলিত অপারেশন বা অন্য কোনও ফ্যালব্যাক চেষ্টা করবেন)) এর সত্য মানটি সত্য।

যখন একটি সমৃদ্ধ তুলনা অপারেটর প্রদত্ত, যদি তারা একই ধরনের, নও পাইথন চেক যদি otherএকটি উপপ্রকার হয়, এবং যদি এটা যে অপারেটর সংজ্ঞায়িত আছে, এটি ব্যবহার করে otherএর পদ্ধতি প্রথম (বিপরীত জন্য <, <=, >=এবং >)। যদি NotImplementedফিরে আসে, তবে এটি বিপরীত পদ্ধতিটি ব্যবহার করে। (এটি একই পদ্ধতির জন্য দুবার পরীক্ষা করে না )) ==অপারেটরটি ব্যবহারের ফলে এই যুক্তিটি সংঘটিত হওয়ার অনুমতি দেয়।


প্রত্যাশা

শব্দার্থকভাবে, আপনার __ne__সমতার জন্য চেকের শর্তাবলী কার্যকর করা উচিত কারণ আপনার শ্রেণীর ব্যবহারকারীরা নিম্নলিখিত ফাংশনগুলি এ এর ​​সমস্ত দৃষ্টান্তের জন্য সমতুল্য আশা করবে:

def negation_of_equals(inst1, inst2):
    """always should return same as not_equals(inst1, inst2)"""
    return not inst1 == inst2

def not_equals(inst1, inst2):
    """always should return same as negation_of_equals(inst1, inst2)"""
    return inst1 != inst2

যে, উপরের উভয় ফাংশন সর্বদা একই ফলাফল প্রদান করা উচিত । তবে এটি প্রোগ্রামারের উপর নির্ভরশীল।

__ne__উপর নির্ভর করে সংজ্ঞায়িত করার সময় অপ্রত্যাশিত আচরণের প্রদর্শন __eq__:

প্রথম সেটআপ:

class BaseEquatable(object):
    def __init__(self, x):
        self.x = x
    def __eq__(self, other):
        return isinstance(other, BaseEquatable) and self.x == other.x

class ComparableWrong(BaseEquatable):
    def __ne__(self, other):
        return not self.__eq__(other)

class ComparableRight(BaseEquatable):
    def __ne__(self, other):
        return not self == other

class EqMixin(object):
    def __eq__(self, other):
        """override Base __eq__ & bounce to other for __eq__, e.g. 
        if issubclass(type(self), type(other)): # True in this example
        """
        return NotImplemented

class ChildComparableWrong(EqMixin, ComparableWrong):
    """__ne__ the wrong way (__eq__ directly)"""

class ChildComparableRight(EqMixin, ComparableRight):
    """__ne__ the right way (uses ==)"""

class ChildComparablePy3(EqMixin, BaseEquatable):
    """No __ne__, only right in Python 3."""

অ-সমতুল্য উদাহরণগুলি ইনস্ট্যান্ট করুন:

right1, right2 = ComparableRight(1), ChildComparableRight(2)
wrong1, wrong2 = ComparableWrong(1), ChildComparableWrong(2)
right_py3_1, right_py3_2 = BaseEquatable(1), ChildComparablePy3(2)

প্রত্যাশিত আচরণ:

(দ্রষ্টব্য: নীচের প্রত্যেকটির প্রতিটি দ্বিতীয় বক্তব্য সমতুল্য এবং অতএব যুক্তিযুক্তভাবে এর আগে যেটির কাছে তা অপ্রয়োজনীয়, আমি তাদের যুক্ত করছি যাতে এই আদেশটি প্রদর্শিত হয় যে যখন অন্যের সাবক্লাস হয় তখন কিছু যায় আসে না। )

এই দৃষ্টান্তগুলি __ne__প্রয়োগ করে ==:

assert not right1 == right2
assert not right2 == right1
assert right1 != right2
assert right2 != right1

পাইথন 3 এর অধীনে এই উদাহরণগুলিও সঠিকভাবে কাজ করে:

assert not right_py3_1 == right_py3_2
assert not right_py3_2 == right_py3_1
assert right_py3_1 != right_py3_2
assert right_py3_2 != right_py3_1

এবং প্রত্যাহার করুন যে এগুলি __ne__বাস্তবায়িত করেছে __eq__- যদিও এটি প্রত্যাশিত আচরণ, বাস্তবায়নটি ভুল:

assert not wrong1 == wrong2         # These are contradicted by the
assert not wrong2 == wrong1         # below unexpected behavior!

অপ্রত্যাশিত আচরণ:

নোট করুন যে এই তুলনাটি উপরের তুলনাগুলির সাথে বিরোধী ( not wrong1 == wrong2)।

>>> assert wrong1 != wrong2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

এবং,

>>> assert wrong2 != wrong1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

__ne__পাইথন 2 এ এড়িয়ে যাবেন না

__ne__পাইথন 2 এ প্রয়োগ করা এড়িয়ে যাবেন না তার প্রমাণের জন্য , এই সমতুল্য বস্তুগুলি দেখুন:

>>> right_py3_1, right_py3_1child = BaseEquatable(1), ChildComparablePy3(1)
>>> right_py3_1 != right_py3_1child # as evaluated in Python 2!
True

উপরের ফলাফল হওয়া উচিত False!

পাইথন 3 উত্স

ডিফল্ট CPython বাস্তবায়ন __ne__হয় typeobject.cমধ্যেobject_richcompare :

case Py_NE:
    /* By default, __ne__() delegates to __eq__() and inverts the result,
       unless the latter returns NotImplemented. */
    if (Py_TYPE(self)->tp_richcompare == NULL) {
        res = Py_NotImplemented;
        Py_INCREF(res);
        break;
    }
    res = (*Py_TYPE(self)->tp_richcompare)(self, other, Py_EQ);
    if (res != NULL && res != Py_NotImplemented) {
        int ok = PyObject_IsTrue(res);
        Py_DECREF(res);
        if (ok < 0)
            res = NULL;
        else {
            if (ok)
                res = Py_False;
            else
                res = Py_True;
            Py_INCREF(res);
        }
    }
    break;

কিন্তু ডিফল্ট __ne__ব্যবহার করে __eq__?

__ne__সি স্তরে পাইথন 3 এর ডিফল্ট বাস্তবায়ন বিশদটি ব্যবহার করে __eq__কারণ উচ্চতর স্তর ==( পাইওবজেক্ট_রিচকম্পার ) কম দক্ষ হবে - এবং তাই এটি অবশ্যই পরিচালনা করতে হবে NotImplemented

যদি __eq__সঠিকভাবে প্রয়োগ করা হয়, তবে এর অস্বীকারও ==সঠিক - এবং এটি আমাদের আমাদের নিম্ন স্তরের প্রয়োগের বিশদ এড়াতে দেয় __ne__

ব্যবহার ==আমাদের মধ্যে আমাদের নিম্ন স্তরের যুক্তিবিজ্ঞান রাখার অনুমতি দেয় এক জায়গা, এবং এড়ানো অ্যাড্রেসিং NotImplementedমধ্যে __ne__

কেউ ভুল করে ধরে নিতে পারে যে ==ফিরে আসতে পারে NotImplemented

এটি আসলে ডিফল্ট বাস্তবায়ন হিসাবে একই যুক্তি ব্যবহার করে __eq__, যা সনাক্তকরণের জন্য পরীক্ষা করে (দেখুন do_richcompare এবং নীচে আমাদের প্রমাণ দেখুন)

class Foo:
    def __ne__(self, other):
        return NotImplemented
    __eq__ = __ne__

f = Foo()
f2 = Foo()

এবং তুলনা:

>>> f == f
True
>>> f != f
False
>>> f2 == f
False
>>> f2 != f
True

কর্মক্ষমতা

আমার শব্দটির জন্য এটি গ্রহণ করবেন না, আসুন আরও বেশি পারফরম্যান্স দেখি:

class CLevel:
    "Use default logic programmed in C"

class HighLevelPython:
    def __ne__(self, other):
        return not self == other

class LowLevelPython:
    def __ne__(self, other):
        equal = self.__eq__(other)
        if equal is NotImplemented:
            return NotImplemented
        return not equal

def c_level():
    cl = CLevel()
    return lambda: cl != cl

def high_level_python():
    hlp = HighLevelPython()
    return lambda: hlp != hlp

def low_level_python():
    llp = LowLevelPython()
    return lambda: llp != llp

আমি মনে করি এই পারফরম্যান্স সংখ্যাগুলি তাদের জন্য কথা বলে:

>>> import timeit
>>> min(timeit.repeat(c_level()))
0.09377292497083545
>>> min(timeit.repeat(high_level_python()))
0.2654011140111834
>>> min(timeit.repeat(low_level_python()))
0.3378178110579029

আপনি যখন বিবেচনা করেন যে low_level_pythonপাইথনে যুক্তি করছেন যা অন্যথায় সি স্তরে পরিচালিত হবে।

কিছু সমালোচকদের প্রতিক্রিয়া

অন্য উত্তরদাতা লিখেছেন:

হারুন হলের বাস্তবায়ন not self == otherএর __ne__পদ্ধতি সঠিক নয় যেমন কখনো আসতে পারেন NotImplemented( not NotImplementedহয় False) এবং সেইজন্য __ne__পদ্ধতি অগ্রাধিকার আছে যা ফিরে পড়া না করতে পারেন __ne__পদ্ধতি যা অগ্রাধিকার নেই।

রয়ে __ne__কখনো ফেরত NotImplementedএটা ভুল দেখা যায় না। পরিবর্তে, আমরা এর সাথে NotImplementedসাম্যের জন্য চেকের মাধ্যমে অগ্রাধিকারটি পরিচালনা করি ==। ধরে ==নেওয়া সঠিকভাবে কার্যকর হয়েছে, আমরা সম্পন্ন করেছি।

not self == other__ne__পদ্ধতির ডিফল্ট পাইথন 3 বাস্তবায়ন হিসাবে ব্যবহৃত হত তবে এটি একটি বাগ ছিল এবং শেডোরেঞ্জার লক্ষ্য করেই জানুয়ারি 2015-তে পাইথন 3.4-এ এটি সংশোধন করা হয়েছিল (সমস্যা # 21408 দেখুন)।

ঠিক আছে, এর ব্যাখ্যা করা যাক।

যেমন পূর্বে উল্লেখ করা হয়েছে, পাইথন 3 ডিফল্টরূপে হ্যান্ডল __ne__করে প্রথমে self.__eq__(other)রিটার্ন NotImplemented(সিঙ্গলটন) যাচাই করা উচিত - যা দিয়ে পরীক্ষা করা উচিত isএবং যদি তা ফিরে আসে তবে অন্যথায় এটি বিপরীতটি ফিরে আসে return ক্লাস মিক্সিন হিসাবে লেখা সেই যুক্তিটি এখানে:

class CStyle__ne__:
    """Mixin that provides __ne__ functionality equivalent to 
    the builtin functionality
    """
    def __ne__(self, other):
        equal = self.__eq__(other)
        if equal is NotImplemented:
            return NotImplemented
        return not equal

সি স্তরের পাইথন এপিআইয়ের নির্ভুলতার জন্য এটি প্রয়োজনীয়, এবং এটি পাইথন 3-এ তৈরি হয়েছিল

অপ্রয়োজনীয় সমস্ত প্রাসঙ্গিক __ne__পদ্ধতিগুলি সরানো হয়েছে যার মধ্যে তাদের নিজস্ব চেক প্রয়োগ করা হয়েছে এবং সেই সাথে __eq__সরাসরি বা মাধ্যমে প্রতিনিধি দেওয়া হয়েছে ==- এবং ==এটি করার সবচেয়ে সাধারণ উপায় ছিল।

প্রতিসম গুরুত্বপূর্ণ কি?

আমাদের ক্রমাগত সমালোচক পরিচালনা করার জন্য কেস করতে একটি আবেগপূর্ণ উদাহরণ NotImplementedমধ্যে __ne__, সব অন্য উপরে প্রতিসাম্য valuing। এর সুস্পষ্ট উদাহরণ সহ যুক্তিটিকে স্টিল-ম্যান করি:

class B:
    """
    this class has no __eq__ implementation, but asserts 
    any instance is not equal to any other object
    """
    def __ne__(self, other):
        return True

class A:
    "This class asserts instances are equivalent to all other objects"
    def __eq__(self, other):
        return True

>>> A() == B(), B() == A(), A() != B(), B() != A()
(True, True, False, True)

সুতরাং, এই যুক্তি দ্বারা, প্রতিসাম্যতা বজায় রাখতে, __ne__পাইথন সংস্করণ নির্বিশেষে আমাদের জটিলটি লিখতে হবে ।

class B:
    def __ne__(self, other):
        return True

class A:
    def __eq__(self, other):
        return True
    def __ne__(self, other):
        result = other.__eq__(self)
        if result is NotImplemented:
            return NotImplemented
        return not result

>>> A() == B(), B() == A(), A() != B(), B() != A()
(True, True, True, True)

স্পষ্টতই আমাদের মনে করা উচিত নয় যে এই দৃষ্টান্তগুলি উভয়ই সমান এবং সমান নয়।

আমি প্রস্তাব দিচ্ছি যে সংবেদনশীল কোড অনুমানের চেয়ে ডকুমেন্টেশনের পরামর্শ অনুসরণ করার চেয়ে প্রতিসামগ্রী কম গুরুত্বপূর্ণ।

তবে, যদি ক এর বুদ্ধিমান বাস্তবায়ন হয় __eq__, তবে আমরা এখনও আমার দিকনির্দেশনাটি এখানে অনুসরণ করতে পারতাম এবং এখনও আমাদের প্রতিসাম্যতা থাকতে পারে:

class B:
    def __ne__(self, other):
        return True

class A:
    def __eq__(self, other):
        return False         # <- this boolean changed... 

>>> A() == B(), B() == A(), A() != B(), B() != A()
(False, False, True, True)

উপসংহার

পাইথন 2 সামঞ্জস্যপূর্ণ কোডের জন্য, ==প্রয়োগ করতে ব্যবহার করুন __ne__। এটি আরও:

  • সঠিক
  • সরল
  • পারফরম্যান্ট

পাইথন 3-তে কেবলমাত্র সি স্তরে নিম্ন-স্তরের অবহেলা ব্যবহার করুন - এটি আরও সাধারণ এবং পারফরম্যান্ট (যদিও প্রোগ্রামার এটি সঠিক কিনা তা নির্ধারণের জন্য দায়বদ্ধ )।

আবার উচ্চ স্তরের পাইথনে নিম্ন-স্তরের যুক্তি লিখবেন না


4
দুর্দান্ত উদাহরণ! আশ্চর্যের অংশটি হ'ল অপারেন্ডগুলির ক্রমটি তাদের কোনও "ম্যাথু " ডানদিকের "প্রতিবিম্বের সাথে কিছু জাদু পদ্ধতির বিপরীতে আলাদা হয় না । যে অংশটি আমি মিস করেছি তার পুনরায় পুনরাবৃত্তি করতে (এবং যার জন্য আমার অনেক সময় ব্যয় হয়েছিল): কোডটি অপারেটরের বামে সুপারক্লাস বা সাবক্লাস রয়েছে কিনা তা বিবেচনা না করে সাবক্লাসের সমৃদ্ধ তুলনা পদ্ধতিটি প্রথমে চেষ্টা করা হয়েছে। এই কারণেই আপনার a1 != c2ফিরে আসা False--- এটি চলেনিa1.__ne__ , তবে c2.__ne__, যা মিশ্রণের __eq__ পদ্ধতিটিকে তুচ্ছ করে । যেহেতু NotImplementedসত্যবাদী, not NotImplementedতাই False
কেভিন জে চেজ

4
আপনার সাম্প্রতিক আপডেটগুলি সফলতার সাথে পারফরম্যান্সের সুবিধাটি প্রদর্শন করে not (self == other), তবে কেউ তর্ক করছেন না এটি দ্রুত নয় (ভাল, পাই 2 তে অন্য কোনও বিকল্পের চেয়ে দ্রুত)। সমস্যাটি কিছু ক্ষেত্রে এটি ভুল ; পাইথন নিজেই করত not (self == other), তবে পরিবর্তিত হয়েছিল কারণ এটি নির্বিচারে সাবক্লাসগুলির উপস্থিতিতে ভুল ছিল । সবচেয়ে দ্রুততম উত্তরটি এখনও ভুল
ShadowRanger

4
সুনির্দিষ্ট উদাহরণটি হ'ল এক ধরনের গুরুত্বহীন really সমস্যাটি হ'ল, আপনার বাস্তবায়নে আপনার __ne__প্রতিনিধিদের __eq__(যদি প্রয়োজন হয় উভয় পক্ষের) এর আচরণ, তবে উভয় " হাল ছেড়ে" দেওয়ার __ne__পরেও এটি কখনই অন্য পক্ষের দিকে ফিরে যায় না__eq__ । সঠিক __ne__প্রতিনিধিদের নিজস্ব নিজস্ব __eq__ , কিন্তু যদি এটি ফিরে আসে NotImplemented, তবে এটি অন্য পক্ষের দিকে ফিরে __ne__উল্টোদিকে পরিবর্তনের পরিবর্তে অন্য পক্ষের দিকে ফিরে যায় __eq__(যেহেতু অন্য পক্ষটি ডেলিগ্রেটে স্পষ্টভাবে অপ্ট-এড না করতে পারে __eq__, এবং আপনার উচিত হবে না) এটির জন্য সিদ্ধান্ত গ্রহণ করা)।
শ্যাডোর্যাঞ্জার

4
@ অ্যারোনহল: আজ এটির পুনর্বিবেচনা করার পরে, আমি মনে করি না যে আপনার বাস্তবায়ন সাধারণত সাবক্লাসগুলির জন্য সমস্যাযুক্ত (এটি একেবারে ভেঙে ফেলার জন্য এটি চূড়ান্তভাবে বিভ্রান্ত হবে, এবং পিতামাতার সম্পূর্ণ জ্ঞান আছে বলে ধরে নেওয়া সাবক্লাসটি এড়াতে সক্ষম হবে) )। তবে আমি আমার উত্তরে একটি অবিচ্ছিন্ন উদাহরণ দিয়েছি। অ আবেগপূর্ণ ক্ষেত্রে SQLAlchemy এর ORM, যেখানে তন্ন তন্ন হয় __eq__না __ne__আয় হয় Trueবা False, বরং একটি প্রক্সি বস্তু (যে "truthy" হতে হবে)। ভুলভাবে বাস্তবায়ন __ne__মানে তুলনা করার জন্য অর্ডার বিষয়গুলি (আপনি কেবলমাত্র একটি ক্রমে একটি প্রক্সি পাবেন)।
শ্যাডোর্যাঞ্জার

4
পরিষ্কার হওয়ার জন্য, 99% ক্ষেত্রে (বা হতে পারে 99.999%) ক্ষেত্রে আপনার সমাধানটি ভাল, এবং (স্পষ্টতই) দ্রুত। তবে যেহেতু এটি জরিমানা হয় না এমন ক্ষেত্রে আপনার নিয়ন্ত্রণ নেই , লাইব্রেরি লেখক হিসাবে যার কোডটি অন্যরা ব্যবহার করতে পারেন (পড়ুন: কেবলমাত্র ব্যক্তিগত ব্যবহারের জন্য সাধারণ এক-অফ স্ক্রিপ্ট এবং মডিউলগুলি ছাড়া) অপারেটর ওভারলোডিংয়ের জন্য সাধারণ চুক্তি মেনে চলার জন্য সঠিক বাস্তবায়নটি ব্যবহার করুন এবং অন্য যে কোনও কোড আপনার মুখোমুখি হতে পারে তার সাথে কাজ করুন। ভাগ্যক্রমে, পাই 3-তে, এটির কোনও কিছুই নেই, কারণ আপনি __ne__সম্পূর্ণ বাদ দিতে পারেন । এখন থেকে এক বছর, পাই 2 মারা যাবে এবং আমরা এটিকে এড়িয়ে চলেছি। :-)
শ্যাডোর্যাঞ্জার

10

কেবল রেকর্ডের জন্য, একটি সাধারণভাবে সঠিক এবং ক্রোম পাই 2 / পাই 3 পোর্টেবলের __ne__মতো দেখতে পাবেন:

import sys

class ...:
    ...
    def __eq__(self, other):
        ...

    if sys.version_info[0] == 2:
        def __ne__(self, other):
            equal = self.__eq__(other)
            return equal if equal is NotImplemented else not equal

এটি __eq__আপনার সংজ্ঞায়িত করতে পারে এমন কোনওটির সাথে কাজ করে:

  • ভিন্ন not (self == other), কিছু বিরক্তিকর / জটিল তুলনা জড়িত ব্যাপারে হস্তক্ষেপ করে না যেখানে জড়িত শ্রেণীর এক পরোক্ষভাবে না যে ফল __ne__ফল হিসাবে একই notউপর __eq__(যেমন SQLAlchemy এর ORM, যেখানে উভয় __eq__এবং __ne__আসতে বিশেষ প্রক্সি বস্তু, না Trueবা False, এবং notফলাফলের চেষ্টা করে সঠিক প্রক্সি অবজেক্টের চেয়ে __eq__ফিরে আসবে False)।
  • ভিন্ন not self.__eq__(other), এই সঠিকভাবে প্রতিনিধিদের __ne__অন্যান্য উদাহরণস্বরূপ যখন self.__eq__আয় NotImplemented( not self.__eq__(other), অতিরিক্ত ভুল হবে কারণ NotImplemented, truthy তাই যখন __eq__কিভাবে তুলনা সম্পাদন করতে জানেন না, __ne__আবার ফিরে আসবে False, যে implying দুটি বস্তুর সমান ছিল আসলে শুধুমাত্র জিজ্ঞাসিত অবজেক্টটির কোনও ধারণা ছিল না, যা সমান নয় এমন একটি ডিফল্ট বোঝায়)

যদি আপনার রিটার্ন __eq__ব্যবহার না করে NotImplementedতবে এটি (অর্থহীন ওভারহেড সহ) কাজ করে, যদি এটি NotImplementedকখনও কখনও ব্যবহার করে তবে এটি এটি সঠিকভাবে পরিচালনা করে। এবং পাইথন সংস্করণ চেকের অর্থ এই যে ক্লাসটি importপাইথন 3-এ থাকলে __ne__তা অপরিবর্তিত রেখে দেওয়া হয়, যার ফলে পাইথনের নেটিভ, দক্ষ ফলব্যাক __ne__বাস্তবায়ন (উপরের একটি সি সংস্করণ) গ্রহণ করতে পারে।


কেন এটি প্রয়োজন

পাইথন ওভারলোডিংয়ের নিয়ম

অন্যান্য সমাধানের পরিবর্তে আপনি কেন এটি করেন তার ব্যাখ্যা কিছুটা তাত্পর্যপূর্ণ। পাইথনের ওভারলোডিং অপারেটর এবং বিশেষত তুলনামূলক অপারেটরদের সম্পর্কে কয়েকটি সাধারণ নিয়ম রয়েছে:

  1. (সমস্ত অপারেটরের ক্ষেত্রে প্রযোজ্য) চলমান সময় LHS OP RHS, চেষ্টা করুন LHS.__op__(RHS)এবং যদি এটি ফিরে আসে NotImplemented, চেষ্টা করুন RHS.__rop__(LHS)। ব্যতিক্রম: যদি শ্রেণীর RHSসাবক্লাস হয় LHSতবে RHS.__rop__(LHS) প্রথমে পরীক্ষা করুন । তুলনা অপারেটরদের ক্ষেত্রে, __eq__এবং __ne__তাদের নিজস্ব "rop" গুলি হয় (তাই জন্য পরীক্ষার অর্ডার __ne__হয় LHS.__ne__(RHS), তারপর RHS.__ne__(LHS), যদি বিপরীত RHSএকটি উপশ্রেণী হয় LHSএর বর্গ)
  2. "অদলবদল করা" অপারেটরের ধারণাটি বাদ দিয়ে অপারেটরগুলির মধ্যে কোনও অন্তর্নিহিত সম্পর্ক নেই। এমনকি একই ক্লাসের উদাহরণস্বরূপ, LHS.__eq__(RHS)ফিরে Trueপরোক্ষভাবে না LHS.__ne__(RHS)আয় False(আসলে, অপারেটার এমনকি বুলিয়ান মান ফেরত দেবার জন্য দায়বদ্ধ করা হয় না; SQLAlchemy মত ORMs ইচ্ছাকৃতভাবে না, ফলে আরো একটি ভাবপূর্ণ সিনট্যাক্স)। পাইথন 3 হিসাবে, ডিফল্ট __ne__বাস্তবায়ন এইভাবে আচরণ করে তবে এটি চুক্তিবদ্ধ নয়; আপনি __ne__এমন উপায়ে ওভাররাইড করতে পারেন যা এর কঠোর বিরোধী নয় __eq__

এটি ওভারলোডিং তুলনাকারীদের ক্ষেত্রে কীভাবে প্রযোজ্য

সুতরাং আপনি যখন কোনও অপারেটরকে ওভারলোড করেন, আপনার দুটি কাজ থাকে:

  1. আপনি কি জানেন অপারেশন নিজেকে বাস্তবায়ন কিভাবে পারেন, তাই হয়, ব্যবহার করে তা করতে শুধুমাত্র (প্রতিনিধি না, পরোক্ষভাবে বা স্পষ্টভাবে কিভাবে তুলনা করতে আপনার নিজস্ব জ্ঞান, অপারেশন অন্য দিকে; এমনটি করা হলেও তা অযথার্থতা এবং / অথবা অসীম recursion ঝুঁকি, আপনি কিভাবে এটি উপর নির্ভর করে)
  2. আপনি কীভাবে নিজেরাই অপারেশন বাস্তবায়ন করবেন তা না জানলে সর্বদা ফিরে NotImplementedআসুন, যাতে পাইথন অন্য অপারেন্ডের বাস্তবায়নে প্রতিনিধি দিতে পারে

সমস্যা not self.__eq__(other)

def __ne__(self, other):
    return not self.__eq__(other)

কখনই অন্য দিকে প্রতিনিধিত্ব করবেন না (এবং __eq__সঠিকভাবে প্রত্যাবর্তন করা হলে এটি ভুল NotImplemented)। যখন self.__eq__(other)রিটার্ন NotImplemented(যা "সত্যবাদী") থাকে, আপনি নিঃশব্দে ফিরে আসেন False, সুতরাং A() != something_A_knows_nothing_aboutফিরে আসে False, যখন something_A_knows_nothing_aboutউদাহরণগুলির সাথে তুলনা করতে হবে কিনা তা যদি পরীক্ষা করা উচিত ছিল Aএবং যদি তা না হয় তবে এটি ফিরে আসা উচিত ছিল True(যেহেতু উভয় পক্ষই জানেন কীভাবে কীভাবে করতে হয়) অপরের সাথে তুলনা করুন, তারা একে অপরের সমান নয় বলে বিবেচিত)। যদি A.__eq__ভুলভাবে কার্যকর করা হয় ( যখন অন্য পক্ষটি স্বীকৃতি না দেয় তার Falseপরিবর্তে প্রত্যাবর্তন করা NotImplemented), তবে এটি Aফিরে আসা True(যেহেতু Aএটি সমান বলে মনে করে না, সুতরাং এটি সমান নয়) এর দিক থেকে "সঠিক" , তবে এটি হতে পারে থেকে ভুলsomething_A_knows_nothing_aboutএর দৃষ্টিকোণ, যেহেতু এটি কখনও জিজ্ঞাসাও করেনি something_A_knows_nothing_about; A() != something_A_knows_nothing_aboutশেষ হয় True, কিন্তু something_A_knows_nothing_about != A()পারে Falseবা অন্য কোনও রিটার্ন মান।

সমস্যা not self == other

def __ne__(self, other):
    return not self == other

আরও সূক্ষ্ম হয়। এটি 99% ক্লাসের জন্য সঠিক হতে চলেছে, এমন সমস্ত ক্লাস সহ যা __ne__যৌক্তিক বিপরীত __eq__। তবে not self == otherউপরে উল্লিখিত উভয় নিয়মই ভেঙে গেছে, যার অর্থ __ne__ এমন ক্লাসগুলির যেখানে লজিক্যাল ইনভার্সের বিপরীতে নয়__eq__ , ফলাফলগুলি আবারও অ-প্রতিসাম্যহীন, কারণ অপারেটরগুলির মধ্যে একটির কাছে কখনই জিজ্ঞাসা করা হয় না যে এটি __ne__আদৌ বাস্তবায়ন করতে পারে কিনা, এমনকি অন্যটি এমনকি অপারেন্ড পারে না। এর সহজ উদাহরণ হ'ল একটি অদ্ভুত শ্রেণি যা সমস্ত তুলনার Falseজন্য ফিরে আসে , তাই এবং উভয়ই ফিরে আসে । এর সঠিক প্রয়োগের সাথে (যেটি আবার ফিরে আসে যখন তুলনা কীভাবে করতে হয় তা জানে না), সম্পর্কটি প্রতিসম হয়; এবংA() == Incomparable()A() != Incomparable()FalseA.__ne__NotImplementedA() != Incomparable()Incomparable() != A()ফলাফলের সাথে সম্মত হন (কারণ প্রাক্তন ক্ষেত্রে, A.__ne__প্রত্যাবর্তন করে NotImplemented, তারপরে Incomparable.__ne__ফিরে আসে , তবে Falseপরবর্তীকালে সরাসরি Incomparable.__ne__ফিরে আসে False)। কিন্তু যখন A.__ne__হিসাবে কার্যকর করা হয় return not self == other, A() != Incomparable()ফিরে আসে True(কারণ A.__eq__ফেরত দেয়, না NotImplemented, তবে Incomparable.__eq__ফিরে আসে Falseএবং এতে A.__ne__উল্টে যায় True), যখন Incomparable() != A()ফেরত দেয়False.

আপনি এখানে কর্মের একটি উদাহরণ দেখতে পারেন ।

স্পষ্টতই, এমন একটি শ্রেণি যা সর্বদা Falseউভয়ের জন্য ফিরে আসে __eq__এবং __ne__কিছুটা অদ্ভুত। তবে পূর্বে উল্লিখিত হিসাবে, __eq__এবং __ne__এমনকি ফেরার প্রয়োজন নেই True/ False; এসকিউএলএলকেমি ওআরএম এর তুলনাকারীদের সাথে ক্লাস রয়েছে যা কোয়েরি বিল্ডিংয়ের জন্য একটি বিশেষ প্রক্সি অবজেক্ট ফিরিয়ে দেয়, না True/ মোটেও Falseনয় (তারা "সত্যবাদী" যদি বুলিয়ান প্রসঙ্গে মূল্যায়ন করা হয় তবে তাদের কখনও এ জাতীয় প্রসঙ্গে মূল্যায়ন করা উচিত নয়)।

জমিদার করতে ব্যর্থ দ্বারা __ne__সঠিকভাবে, আপনি হবে , যে সাজানোর শ্রেণীর বিরতি কোড হিসাবে:

 results = session.query(MyTable).filter(MyTable.fieldname != MyClassWithBadNE())

কাজ করবে (ধরে নিই যে এসকিউএএলএল্কেমি কীভাবে MyClassWithBadNEকোনও এসকিউএল স্ট্রিংটি সন্নিবেশ করাতে জানে ; এটি কোনওভাবে MyClassWithBadNEসহযোগিতা না করে টাইপ অ্যাডাপ্টারের সাহায্যে করা যেতে পারে ), প্রত্যাশিত প্রক্সি অবজেক্টটি পাস করার filterসময়:

 results = session.query(MyTable).filter(MyClassWithBadNE() != MyTable.fieldname)

filterসমভূমি পেরিয়ে যাওয়া শেষ হবে False, কারণ self == otherপ্রক্সি অবজেক্টটি ফিরিয়ে দেয় এবং not self == otherসত্যবাদী প্রক্সি অবজেক্টকে রূপান্তর করে False। আশা করি, filterঅবৈধ আর্গুমেন্টের মতো পরিচালনা করার ক্ষেত্রে একটি ব্যতিক্রম ছুঁড়ে ফেলা হবে False। যদিও আমি নিশ্চিত যে অনেকে তুলনা করার বাম দিকে নিয়মিত MyTable.fieldname হওয়া উচিত তর্ক করবে , সত্যটি এখনও অব্যাহত রয়েছে যে সাধারণ ক্ষেত্রে এটি প্রয়োগের কোনও প্রোগ্রামিক কারণ নেই এবং সঠিক জেনেরিক কোনওভাবেই __ne__কাজ করবে, যখন return not self == otherকেবল কাজ করবে এক ব্যবস্থা।


4
একমাত্র সঠিক, সম্পূর্ণ এবং সৎ (দুঃখিত @ অ্যারোনহল) উত্তর এটি গ্রহণযোগ্য উত্তর হওয়া উচিত।
ম্যাগগিরো

তুমি আমার আপডেট উত্তর ব্যবহার করে যা আমি তোমার চেয়ে শক্তিশালী যুক্তি মনে দ্বারা আগ্রহী হতে পারে Incomparableযেহেতু এই শ্রেণীর বিরতি বর্গ সম্পূরক মধ্যে সম্পর্ক !=এবং ==অপারেটরদের এবং সেইজন্য একটি অবৈধ বা "আবেগপূর্ণ" উদাহরণ বিবেচনা করা যেতে পারে মত @AaronHall লাগাতে হবে। এবং আমি স্বীকার করি যে @ অ্যারোনহলের একটি বক্তব্য রয়েছে যখন তিনি উল্লেখ করেছিলেন যে আপনার এসকিউএএলএলচেমি যুক্তিটি অপ্রাসঙ্গিক হিসাবে বিবেচনা করা যেতে পারে যেহেতু এটি অ-বুলিয়ান প্রসঙ্গে রয়েছে। (আপনার আর্গুমেন্ট এখনও খুব আকর্ষণীয় এবং ভাল চিন্তা আছে।)
Maggyero

4

সঠিক __ne__বাস্তবায়ন

@ শ্যাডোর্যাঙ্গারের বিশেষ পদ্ধতির বাস্তবায়ন __ne__সঠিক পদ্ধতি :

def __ne__(self, other):
    result = self.__eq__(other)
    if result is not NotImplemented:
        return not result
    return NotImplemented

পাইথন ডকুমেন্টেশনে যেমন বলা হয়েছে তেমন __ne__ পাইথন ৩.৪ থেকে বিশেষ পদ্ধতির ডিফল্ট বাস্তবায়নও এটি ঘটে :

ডিফল্টরূপে, __ne__()প্রতিনিধিরা __eq__()ফলাফলটি না করে উল্টে দেয় NotImplemented

আরও মনে রাখবেন যে NotImplementedঅসমর্থিত অপারেন্ডগুলির জন্য মান ফিরিয়ে দেওয়া বিশেষ পদ্ধতির সাথে সুনির্দিষ্ট নয় __ne__। প্রকৃতপক্ষে, সমস্ত বিশেষ তুলনা পদ্ধতি 1 এবং বিশেষ সংখ্যাসূচক পদ্ধতি 2NotImplemented গুলির পাইথন ডকুমেন্টেশনে উল্লিখিত অসমর্থিত অপারেশনগুলির জন্য মানটি ফিরিয়ে দেওয়া উচিত :

NotImplemented

এই ধরণের একক মান রয়েছে। এই মান সহ একটি একক অবজেক্ট আছে। এই অবজেক্টটি বিল্ট-ইন নামের মাধ্যমে অ্যাক্সেস করা হয়েছে NotImplemented। সংখ্যক পদ্ধতিগুলি এবং সমৃদ্ধ তুলনা পদ্ধতিগুলি যদি সরবরাহিত অপারেন্ডগুলির জন্য ক্রিয়াকলাপটি বাস্তবায়ন না করে তবে এই মানটি ফিরিয়ে আনতে হবে। (দোভাষী তারপরে অপারেটরের উপর নির্ভর করে প্রতিফলিত অপারেশন বা অন্য কোনও ফ্যালব্যাক চেষ্টা করবেন)) এর সত্য মানটি সত্য।

পাইথন ডকুমেন্টেশনে বিশেষ সংখ্যা সংক্রান্ত পদ্ধতির উদাহরণ দেওয়া হয়েছে :

class MyIntegral(Integral):

    def __add__(self, other):
        if isinstance(other, MyIntegral):
            return do_my_adding_stuff(self, other)
        elif isinstance(other, OtherTypeIKnowAbout):
            return do_my_other_adding_stuff(self, other)
        else:
            return NotImplemented

    def __radd__(self, other):
        if isinstance(other, MyIntegral):
            return do_my_adding_stuff(other, self)
        elif isinstance(other, OtherTypeIKnowAbout):
            return do_my_other_adding_stuff(other, self)
        elif isinstance(other, Integral):
            return int(other) + int(self)
        elif isinstance(other, Real):
            return float(other) + float(self)
        elif isinstance(other, Complex):
            return complex(other) + complex(self)
        else:
            return NotImplemented

1 বিশেষ তুলনা পদ্ধতি: __lt__, __le__, __eq__, __ne__, __gt__এবং __ge__

2 বিশেষ সাংখ্যিক পদ্ধতি: __add__, __sub__, __mul__, __matmul__, __truediv__, __floordiv__, __mod__, __divmod__, __pow__, __lshift__, __rshift__, __and__, __xor__, __or__এবং তাদের __r*__প্রতিফলিত এবং __i*__ইন-জায়গা প্রতিরূপ।

ভুল __ne__বাস্তবায়ন # 1

@ ফালমারির বিশেষ পদ্ধতি প্রয়োগের __ne__বিষয়টি ভুল:

def __ne__(self, other):
    return not self.__eq__(other)

এই বাস্তবায়নের ক্ষেত্রে সমস্যাটি হ'ল এটি __ne__অন্য অপারেন্ডের বিশেষ পদ্ধতিতে ফিরে আসে না কারণ এটি কখনই মান দেয় না NotImplemented(এক্সপ্রেশনটি not self.__eq__(other)মূল্যকে মূল্যায়ন করে Trueবা Falseতার সাপ এক্সপ্রেসন যখন self.__eq__(other)মূল্যকে মূল্যায়ন করে NotImplementedযেহেতু অভিব্যক্তিটি bool(NotImplemented)মূল্যকে মূল্যায়ণ করে True)। মান বুলিয়ান মূল্যায়ন NotImplementedভঙ্গ সম্পূরক তুলনা অপারেটরদের মধ্যে সম্পর্ক !=এবং ==:

class Correct:

    def __ne__(self, other):
        result = self.__eq__(other)
        if result is not NotImplemented:
            return not result
        return NotImplemented


class Incorrect:

    def __ne__(self, other):
        return not self.__eq__(other)


x, y = Correct(), Correct()
assert (x != y) is not (x == y)

x, y = Incorrect(), Incorrect()
assert (x != y) is not (x == y)  # AssertionError

ভুল __ne__বাস্তবায়ন # 2

@ বিশেষ পদ্ধতিটি অ্যারনহল এর বাস্তবায়নও __ne__ভুল:

def __ne__(self, other):
    return not self == other

এই প্রয়োগের ক্ষেত্রে সমস্যাটি হ'ল এটি সরাসরি __eq__অন্য অপারেন্ডের বিশেষ পদ্ধতিতে ফিরে আসে , অন্য অপারেন্ডের বিশেষ পদ্ধতিটিকে বাইপাস করে __ne__যেহেতু এটি কখনই মান দেয় না NotImplemented(এক্সপ্রেশনটি অন্য অপারেন্ডের not self == otherবিশেষ পদ্ধতিতে পড়ে __eq__এবং মূল্যায়ন করে) মান Trueবা False)। কোনও পদ্ধতিকে বাইপাস করা ভুল কারণ এই পদ্ধতির অজানাটির অবস্থা আপডেট করার মতো পার্শ্ব প্রতিক্রিয়া থাকতে পারে :

class Correct:

    def __init__(self):
        self.counter = 0

    def __ne__(self, other):
        self.counter += 1
        result = self.__eq__(other)
        if result is not NotImplemented:
            return not result
        return NotImplemented


class Incorrect:

    def __init__(self):
        self.counter = 0

    def __ne__(self, other):
        self.counter += 1
        return not self == other


x, y = Correct(), Correct()
assert x != y
assert x.counter == y.counter

x, y = Incorrect(), Incorrect()
assert x != y
assert x.counter == y.counter  # AssertionError

তুলনা অপারেশন বোঝা

গণিত, একটি বাইনারি সম্পর্ক আর একটি সেট উপর এক্স আদেশ জোড়া (একটি সেট এক্সY মধ্যে)  এক্স 2 । বিবৃতি ( এক্সY ) এ  আর সার্চ " এক্স হয় আর করার সংক্রান্ত Y " এবং দ্বারা প্রকাশ করা হয় xRy

একটি বাইনারি সম্পর্ক প্রোপার্টি আর একটি সেট উপর এক্স :

  • আর নয় আত্মবাচক যখন সবার জন্য এক্স মধ্যে এক্স , xRx
  • আর হয় irreflexive (নামেও কঠোর ) সমস্ত যখন এক্স মধ্যে এক্স , না xRx
  • আর নয় প্রতিসম সবার জন্য যখন এক্স এবং ওয়াই মধ্যে এক্স , যদি xRy তারপর yRx
  • আর নয় antisymmetric সবার জন্য যখন এক্স এবং ওয়াই মধ্যে এক্স , যদি xRy এবং yRx তারপর এক্স  =  Y
  • আর নয় সকর্মক যখন সবার জন্য এক্স , Y এবং z- র মধ্যে এক্স , যদি xRy এবং yRz তারপর xRz
  • আর নয় connex (নামেও মোট ) সমস্ত যখন এক্স এবং ওয়াই মধ্যে এক্স , xRy বা yRx
  • আর একটি সমতুল্য সম্পর্ক হয় যখন আর রিফ্লেক্সিভ, প্রতিসম এবং ট্রানজিটিভ হয়।
    উদাহরণস্বরূপ, =। তবে only কেবলমাত্র প্রতিসম হয়।
  • আর হ'ল অর্ডার রিলেশন, যখন আর রিফ্লেক্সিভ, এন্টিসিমমেট্রিক এবং ট্রানজিটিভ হয়।
    উদাহরণস্বরূপ, ≤ এবং ≥।
  • আর হ'ল কঠোর অর্ডার রিলেশন, যখন আর অপ্রয়োজনীয়, অ্যান্টিসিমমেট্রিক এবং ট্রানজিটিভ হয়।
    উদাহরণস্বরূপ, <এবং>। তবে only কেবল অপ্রয়োজনীয়।

একটি সেট এক্স- তে দুটি বাইনারি সম্পর্ক আর এবং এস-এর জন্য অপারেশন :

  • বিপরীতটি এর আর বাইনারি সম্পর্ক নেই আর টি  = {( Yএক্স ) | xRy } এক্স এর উপরে ।
  • সম্পূরক এর আর বাইনারি সম্পর্ক ¬ হয় আর  = {( এক্সY ) | xRy X X এর চেয়ে বেশি নয় ।
  • ইউনিয়ন এর আরএস বাইনারি সম্পর্ক নেই আর  ∪  এস  = {( এক্সY ) | xRy বা xSy } X এর উপরে ।

তুলনামূলক সম্পর্কের মধ্যে সম্পর্ক যা সর্বদা বৈধ:

  • 2 পরিপূরক সম্পর্ক: = এবং each একে অপরের পরিপূরক;
  • Con টি রূপান্তরকারী সম্পর্ক: = এটিই একটি রূপান্তরকারী, itself নিজেই একটি রূপান্তর, <এবং> একে অপরের কনভার্স এবং; এবং ≥ একে অপরের কনভার্স;
  • 2 ইউনিয়ন সম্পর্ক: ≤ হ'ল <এবং =, এবং ≥ হল> এবং = এর মিল।

তুলনামূলক সম্পর্কের মধ্যে সম্পর্ক যা কেবল সংযুক্তি আদেশের জন্য বৈধ :

  • 4 পরিপূরক সম্পর্ক: <এবং each একে অপরের পরিপূরক এবং> এবং একে অপরের পরিপূরক।

তাই সঠিকভাবে করার জন্য পাইথন মধ্যে বাস্তবায়ন তুলনা অপারেটরদের ==, !=, <, >, <=, এবং >=তুলনা সম্পর্ক সংশ্লিষ্ট =, ≠, <,>, ≤ ও ≥, সর্বোপরি গাণিতিক বৈশিষ্ট্য এবং সম্পর্ক রাখা উচিত নয়।

একটি তুলনামূলক ক্রিয়াকলাপটিকে এর অপারেশনগুলির মধ্যে একটির শ্রেণির x operator yবিশেষ তুলনা পদ্ধতি __operator__বলে:

class X:

    def __operator__(self, other):
        # implementation

যেহেতু আর হয় আত্মবাচক বোঝা xRx , একটি আত্মবাচক তুলনা অপারেশন x operator y( x == y, x <= yএবং x >= y) অথবা আত্মবাচক বিশেষ তুলনা পদ্ধতি কল x.__operator__(y)( x.__eq__(y), x.__le__(y)এবং x.__ge__(y)) মান নির্ণয় করা উচিত Trueযদি xএবং yযে যদি অভিব্যক্তি, অভিন্ন x is yমূল্যায়ন করার True। যেহেতু আর হয় irreflexive না বোঝা xRx , একটি irreflexive তুলনা অপারেশন x operator y( x != y, x < yএবং x > y) অথবা irreflexive বিশেষ তুলনা পদ্ধতি কল x.__operator__(y)( x.__ne__(y), x.__lt__(y)এবং x.__gt__(y)) মান নির্ণয় করা উচিতFalseযদি xএবং yঅভিন্ন হয়, এটি হল যদি অভিব্যক্তিটি x is yমূল্যায়ন করে True। আত্মবাচক সম্পত্তি তুলনা অপারেটর জন্য পাইথন দ্বারা বিবেচনা করা হয় ==এবং বিশেষ তুলনা পদ্ধতি যুক্ত __eq__কিন্তু আশ্চর্যজনক বিবেচনা করা তুলনা অপারেটরদের জন্য <=এবং >=এবং বিশেষ তুলনা পদ্ধতি যুক্ত __le__এবং __ge__, এবং irreflexive সম্পত্তি তুলনা অপারেটর জন্য পাইথন দ্বারা বিবেচনা করা হয় !=এবং বিশেষ তুলনা পদ্ধতি যুক্ত __ne__কিন্তু তুলনা অপারেটর এবং এবং সম্পর্কিত বিশেষ তুলনা পদ্ধতি এবং জন্য আশ্চর্যজনকভাবে বিবেচনা করা হয় না<>__lt____gt__পাইথন ডকুমেন্টেশনে বর্ণিত হিসাবে উপেক্ষা করা তুলনা অপারেটরগুলি পরিবর্তে ব্যতিক্রম TypeError(এবং সম্পর্কিত বিশেষ তুলনা পদ্ধতিগুলির পরিবর্তে মানটি ফেরত দেয় NotImplemented) বাড়িয়ে তোলে :

সমতা তুলনা ( ==এবং !=) এর জন্য ডিফল্ট আচরণ বস্তুর সনাক্তকরণের উপর ভিত্তি করে। অতএব, একই পরিচয়ের সাথে উদাহরণগুলির সমতা তুলনা সমতাতে ফলাফল করে এবং বিভিন্ন পরিচয়ের সাথে দৃষ্টান্তের সাম্যের তুলনা অসমতার ফলস্বরূপ। এই ডিফল্ট আচরণের জন্য একটি অনুপ্রেরণা হ'ল ইচ্ছা যে সমস্ত বস্তুগুলি প্রতিচ্ছবিযুক্ত (যেমন x is yবোঝা যায় x == y)।

একটি ডিফল্ট অর্ডার তুলনা ( <, >, <=, এবং >=) দেওয়া হয় না; একটি প্রচেষ্টা উত্থাপন TypeError। এই ডিফল্ট আচরণের জন্য অনুপ্রেরণা হ'ল সাম্যতার মতো একই রকম আক্রমণকারীের অভাব। [এই যেহেতু ভুল <=এবং >=মত আত্মবাচক হয় ==, এবং <এবং >মত irreflexive হয় !=।]

ক্লাসটি objectবিশেষ তুলনা পদ্ধতিগুলির ডিফল্ট বাস্তবায়ন সরবরাহ করে যা পাইথন ডকুমেন্টেশনে বর্ণিত হিসাবে এটির সমস্ত সাবক্লাস দ্বারা উত্তরাধিকার সূত্রে প্রাপ্ত :

object.__lt__(self, other)
object.__le__(self, other)
object.__eq__(self, other)
object.__ne__(self, other)
object.__gt__(self, other)
object.__ge__(self, other)

এগুলি তথাকথিত "সমৃদ্ধ তুলনা" পদ্ধতিগুলি। অপারেটর প্রতীক এবং পদ্ধতির নামের মধ্যে যোগাযোগটি নিম্নরূপ: x<yকল x.__lt__(y), x<=yকল x.__le__(y), x==yকল x.__eq__(y), x!=yকল x.__ne__(y), x>yকল x.__gt__(y), x>=y কল এবং কল x.__ge__(y)

একটি সমৃদ্ধ তুলনামূলক পদ্ধতিটি NotImplementedযদি প্রদত্ত যুগল যুক্তির জন্য ক্রিয়াকলাপটি বাস্তবায়ন না করে তবে সিঙ্গলটনে ফিরে আসতে পারে।

[…]

এই পদ্ধতির কোনও অদল-বদল সংস্করণ নেই (যখন বাম আর্গুমেন্ট অপারেশন সমর্থন করে না তবে ডান আর্গুমেন্টটি ব্যবহার করে); বরং, __lt__()এবং __gt__()একে অপরের প্রতিবিম্ব, __le__()এবং __ge__()একে অপরের প্রতিবিম্ব, এবং __eq__()এবং __ne__()তাদের নিজস্ব প্রতিবিম্ব হয়। অপারেন্ডগুলি বিভিন্ন ধরণের হয় এবং ডান অপারেন্ডের ধরণটি বাম অপারেন্ডের ধরণের প্রত্যক্ষ বা অপ্রত্যক্ষ সাবক্লাস হলে ডান অপারেন্ডের প্রতিফলিত পদ্ধতির অগ্রাধিকার থাকে, অন্যথায় বাম অপারেন্ডের পদ্ধতির অগ্রাধিকার থাকে। ভার্চুয়াল সাবক্লাসিং বিবেচনা করা হয় না।

যেহেতু আর = ( আর টি টি ) টি , একটি তুলনা xRy কনভার্স তুলনা yR টি এক্স এর সমান (পাইথন ডকুমেন্টেশনে অনানুষ্ঠানিকভাবে "প্রতিফলিত" নামকরণ করা হয়েছে)। সুতরাং তুলনা অপারেশনের ফলাফল গণনা করার জন্য দুটি উপায় রয়েছে x operator y: হয় কল করুন x.__operator__(y)বা y.__operatorT__(x)। পাইথন নিম্নলিখিত কম্পিউটিং কৌশল ব্যবহার করে:

  1. x.__operator__(y)ডান অপারেন্ডের শ্রেণি বাম অপারেন্ডের শ্রেণীর বংশধর না হলে এটি কল করে, যদি এটি কল করে y.__operatorT__(x)( ক্লাসগুলি তাদের পূর্বপুরুষদের কনভার্সের বিশেষ তুলনা পদ্ধতিকে ওভাররাইড করতে দেয় )।
  2. যদি অপারেশনগুলি xএবং yঅসমর্থিত (ফেরত মান দ্বারা নির্দেশিত NotImplemented) হয়, তবে এটি কনভার্সের বিশেষ তুলনা পদ্ধতিটিকে 1 ম ফলব্যাক হিসাবে ডাকে ।
  3. অপারেশনগুলি xএবং yঅসমর্থিত (ফেরতের মান দ্বারা নির্দেশিত NotImplemented), এটি TypeErrorতুলনামূলক অপারেটর ব্যতীত ব্যতিক্রম উত্থাপন করে ==এবং !=যার জন্য এটি যথাক্রমে অপারেটরগুলির পরিচয় এবং অ-পরিচয় পরীক্ষা করে xএবং দ্বিতীয় ফলব্যাকy হিসাবে (এবং এর রিফ্লেসিভিটি সম্পত্তি লাভ করে এবং অপ্রয়োজনীয় সম্পত্তি ) property==!=
  4. এটি ফলাফলটি ফেরত দেয়।

CPython সালে এই সি কোডে বাস্তবায়িত হয় , যা (নামের সাথে পাইথন কোড অনুদিত করা যাবে eqজন্য ==, neজন্য !=, ltজন্য <, gtজন্য >, leজন্য <=এবং geজন্য >=):

def eq(left, right):
    if type(left) != type(right) and isinstance(right, type(left)):
        result = right.__eq__(left)
        if result is NotImplemented:
            result = left.__eq__(right)
    else:
        result = left.__eq__(right)
        if result is NotImplemented:
            result = right.__eq__(left)
    if result is NotImplemented:
        result = left is right
    return result
def ne(left, right):
    if type(left) != type(right) and isinstance(right, type(left)):
        result = right.__ne__(left)
        if result is NotImplemented:
            result = left.__ne__(right)
    else:
        result = left.__ne__(right)
        if result is NotImplemented:
            result = right.__ne__(left)
    if result is NotImplemented:
        result = left is not right
    return result
def lt(left, right):
    if type(left) != type(right) and isinstance(right, type(left)):
        result = right.__gt__(left)
        if result is NotImplemented:
            result = left.__lt__(right)
    else:
        result = left.__lt__(right)
        if result is NotImplemented:
            result = right.__gt__(left)
    if result is NotImplemented:
        raise TypeError(
            f"'<' not supported between instances of '{type(left).__name__}' "
            f"and '{type(right).__name__}'"
        )
    return result
def gt(left, right):
    if type(left) != type(right) and isinstance(right, type(left)):
        result = right.__lt__(left)
        if result is NotImplemented:
            result = left.__gt__(right)
    else:
        result = left.__gt__(right)
        if result is NotImplemented:
            result = right.__lt__(left)
    if result is NotImplemented:
        raise TypeError(
            f"'>' not supported between instances of '{type(left).__name__}' "
            f"and '{type(right).__name__}'"
        )
    return result
def le(left, right):
    if type(left) != type(right) and isinstance(right, type(left)):
        result = right.__ge__(left)
        if result is NotImplemented:
            result = left.__le__(right)
    else:
        result = left.__le__(right)
        if result is NotImplemented:
            result = right.__ge__(left)
    if result is NotImplemented:
        raise TypeError(
            f"'<=' not supported between instances of '{type(left).__name__}' "
            f"and '{type(right).__name__}'"
        )
    return result
def ge(left, right):
    if type(left) != type(right) and isinstance(right, type(left)):
        result = right.__le__(left)
        if result is NotImplemented:
            result = left.__ge__(right)
    else:
        result = left.__ge__(right)
        if result is NotImplemented:
            result = right.__le__(left)
    if result is NotImplemented:
        raise TypeError(
            f"'>=' not supported between instances of '{type(left).__name__}' "
            f"and '{type(right).__name__}'"
        )
    return result

যেহেতু আর = ¬ (¬ আর ), একটি তুলনা xRy পরিপূরক তুলনা ¬ ( x ¬ Ry ) এর সমতুল্য । ≠ = এর পরিপূরক, সুতরাং ডিফল্টরূপে সমর্থিত অপারেশনগুলির জন্য __ne__বিশেষ পদ্ধতির ক্ষেত্রে বিশেষ পদ্ধতিটি প্রয়োগ করা হয় __eq__, অন্য অন্যান্য তুলনামূলক পদ্ধতিগুলি ডিফল্টরূপে স্বাধীনভাবে প্রয়োগ করা হয় (সত্য যে ≤ <এবং = এর মিলন, এবং ≥ হ'ল> এবং = এর মিলনটি আশ্চর্যজনকভাবে বিবেচনা করা হয় না , যার অর্থ বর্তমানে বিশেষ পদ্ধতিগুলি __le__এবং __ge__ব্যবহারকারীর প্রয়োগ করা উচিত), পাইথন ডকুমেন্টেশনে বর্ণিত :

ডিফল্টরূপে, __ne__()প্রতিনিধিরা __eq__()ফলাফলটি না করে উল্টে দেয় NotImplemented। তুলনা অপারেটরগুলির মধ্যে অন্য কোনও অন্তর্নিহিত সম্পর্ক নেই, উদাহরণস্বরূপ, সত্যটি (x<y or x==y)বোঝায় না x<=y

সিপিথনে এটি সি কোডে প্রয়োগ করা হয় , যা পাইথন কোডে অনুবাদ করা যেতে পারে:

def __eq__(self, other):
    return self is other or NotImplemented
def __ne__(self, other):
    result = self.__eq__(other)
    if result is not NotImplemented:
        return not result
    return NotImplemented
def __lt__(self, other):
    return NotImplemented
def __gt__(self, other):
    return NotImplemented
def __le__(self, other):
    return NotImplemented
def __ge__(self, other):
    return NotImplemented

সুতরাং ডিফল্ট হিসাবে:

  • একটি তুলনা অপারেশন তুলনা অপারেটর ব্যতীত x operator yব্যতিক্রম উত্থাপন করে এবং যার জন্য এটি যথাক্রমে অপারেটরগুলির পরিচয় এবং অ-পরিচয় দেয় এবং ;TypeError==!=xy
  • একটি বিশেষ তুলনা পদ্ধতি কল x.__operator__(y)মান NotImplementedবিশেষ তুলনা পদ্ধতি ছাড়া __eq__এবং __ne__যার জন্য যথাক্রমে ফেরৎ Trueএবং Falseoperands যদি xএবং yযথাক্রমে অভিন্ন এবং অ অভিন্ন এবং মান NotImplementedঅন্যথায়।

আপনার শেষ উদাহরণের জন্য: "যেহেতু এই প্রয়োগটি __ne__পদ্ধতিটির পূর্বনির্ধারিত প্রয়োগের আচরণের প্রতিরূপ তৈরি করতে ব্যর্থ হয় যখন __eq__পদ্ধতিটি নয়টি প্রয়োগ করে ফিরে আসে, এটি ভুল is" - Aনিঃশর্ত সাম্যতা সংজ্ঞায়িত করে। এইভাবে A() == B(),। সুতরাং A() != B() মিথ্যা হওয়া উচিত , এবং এটি হয় । প্রদত্ত উদাহরণগুলি হ'ল প্যাথলজিকালগুলি (যেমন __ne__কোনও স্ট্রিং ফিরিয়ে দেওয়া উচিত নয় এবং এর __eq__উপর নির্ভর করা উচিত নয়) __ne__বরং __ne__নির্ভর করা উচিত __eq__, যা পাইথন 3-এ ডিফল্ট প্রত্যাশা। আপনি আমার মন পরিবর্তন না করতে পারা পর্যন্ত আমি এই উত্তরে এখনও -1 আছি।
হারুন হলের

@AaronHall থেকে পাইথন ভাষা রেফারেন্স : "একজন ধনী তুলনা পদ্ধতি Singleton ফেরত দিতে পারেন NotImplementedযদি এটা আর্গুমেন্ট একটি প্রদত্ত যুগল জন্য অপারেশন বাস্তবায়ন নেই কনভেনশন দ্বারা,। Falseএবং Trueএকটি সফল তুলনা জন্য ফিরিয়ে আনা হয়। যাইহোক, এই পদ্ধতি কোনো মান আসতে পারেন সুতরাং, যদি তুলনামূলক অপারেটরটি বুলিয়ান প্রসঙ্গে ব্যবহার করা হয় (যেমন, যদি একটি বিবৃতি শর্তে), পাইথন bool()ফলাফলটি সত্য বা মিথ্যা কিনা তা নির্ধারণের জন্য মানটি কল করবে ""
ম্যাগগিরো

চূড়ান্ত উদাহরণে দুটি শ্রেণি রয়েছে, Bএটি সমস্ত চেকের জন্য সত্যবাদী স্ট্রিং দেয় __ne__এবং এটি সমস্ত পরীক্ষায় Aফিরে আসে । এটি একটি প্যাথোলজিকাল দ্বন্দ্ব। এই জাতীয় দ্বন্দ্বের অধীনে, ব্যতিক্রম উত্থাপন করা ভাল। জ্ঞান ছাড়া , সম্মান করার কোন বাধ্যবাধকতা বয়সী 'র বাস্তবায়ন প্রতিসাম্য উদ্দেশ্যে। উদাহরণের সেই মুহুর্তে, কীভাবে প্রয়োগসমূহ আমার কাছে অপ্রাসঙ্গিক। আপনার বক্তব্য তৈরি করার জন্য দয়া করে একটি ব্যবহারিক, অ-প্যাথলজিকাল কেস সন্ধান করুন। আপনাকে সম্বোধনের জন্য আমি আমার উত্তর আপডেট করেছি। True__eq__BAB__ne__A__ne__
হারুন হলের

এসকিউএলএলচেমির ব্যবহারের ক্ষেত্রটি একটি ডোমেন নির্দিষ্ট ভাষার জন্য। যদি কেউ এই জাতীয় ডিএসএল ডিজাইন করে থাকেন তবে কেউ এখানে সমস্ত পরামর্শ উইন্ডো থেকে ফেলে দিতে পারে। এই দুর্বল উপমাটিকে নির্যাতন চালিয়ে যাওয়ার জন্য, আপনার উদাহরণটি প্রত্যাশা করছে যে কোনও প্লেন অর্ধেক সময় পিছনের দিকে উড়ে যাবে, এবং আমার কেবল তাদের সামনে অগ্রসর হওয়ার প্রত্যাশা করবে এবং আমি মনে করি এটি একটি যুক্তিসঙ্গত নকশার সিদ্ধান্ত। আমি মনে করি আপনি যে উদ্বেগ উত্থাপন করছেন তা অযৌক্তিক এবং পিছনের দিকে।
হারুন হলের

-1

সব যদি __eq__, __ne__, __lt__, __ge__, __le__, এবং __gt__বর্গ জন্য জানার জন্য হয় তাহলে, শুধুমাত্র বাস্তবায়ন __cmp__পরিবর্তে। অন্যথায়, আপনি যেমনটি করছেন ঠিক তেমন করুন, ড্যানিয়েল ডিপাওলো বলেছিলেন (কারণ আমি এটি দেখার পরিবর্তে এটি পরীক্ষা করছিলাম;))


12
__cmp__()বিশেষ পদ্ধতি আর পাইথন 3.x সমর্থিত যাতে আপনি সমৃদ্ধ তুলনা অপারেটর ব্যবহার করে ব্যবহার করতে পারেন কর্তব্য।
ডন ও'ডনেল

8
অথবা বিকল্প হিসাবে আপনি পাইথন ২.7 বা ৩.x এ থাকলে ফান্টাকুলস.টোটাল_র্ডারিংয়ের সাজসজ্জারটিও বেশ কার্যকর।
আদম পার্কিন

সতর্ক থাকুন জন্য ধন্যবাদ. যদিও আমি গত দেড় বছরে সেই লাইন ধরে অনেকগুলি জিনিস উপলব্ধি করেছি। ;)
কার্ল নচেটেল
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.