পাইথন ক্লাসে সমতা ("সমতা") সমর্থন করার দুর্দান্ত উপায়


421

যখন কাস্টম শ্রেণীর লেখার এটা প্রায়ই মাধ্যমে সমানতা করার অনুমতি গুরুত্বপূর্ণ ==এবং !=অপারেটর। পাইথনে , যথাক্রমে __eq__এবং __ne__বিশেষ পদ্ধতিগুলি প্রয়োগ করে এটি সম্ভব হয়েছে। এটি করার সবচেয়ে সহজ উপায়টি হ'ল নিম্নলিখিত পদ্ধতিটি:

class Foo:
    def __init__(self, item):
        self.item = item

    def __eq__(self, other):
        if isinstance(other, self.__class__):
            return self.__dict__ == other.__dict__
        else:
            return False

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

আপনি কি এটি করার আরও মার্জিত উপায় সম্পর্কে জানেন? ওপরের তুলনা করার উপরোক্ত পদ্ধতিটি ব্যবহার করে আপনি কোনও বিশেষ অসুবিধা সম্পর্কে জানেন __dict__?

দ্রষ্টব্য : কিছুটা স্পষ্টতা - কখন __eq__এবং __ne__অপরিজ্ঞাত হয়, আপনি এই আচরণটি খুঁজে পাবেন:

>>> a = Foo(1)
>>> b = Foo(1)
>>> a is b
False
>>> a == b
False

এটি হ'ল a == bমূল্যায়ন করে Falseকারণ এটি সত্যই সঞ্চালিত হয় a is b, পরিচয়ের একটি পরীক্ষা (যেমন, "কি aএকই জিনিস b?")।

যখন __eq__এবং __ne__সংজ্ঞায়িত করা হয়, আপনি এই আচরণটি খুঁজে পাবেন (যা আমরা পরে যা করছি):

>>> a = Foo(1)
>>> b = Foo(1)
>>> a is b
False
>>> a == b
True

6
+1, কারণ আমি জানতাম না যে ডিক == এর জন্য সদস্য পদে সমতা ব্যবহার করেছে, আমি ধরে নিয়েছিলাম যে এটি কেবল একই বস্তুর ডিক্টের জন্য তাদের সমান গণনা করেছে। আমার ধারণা এটি সুস্পষ্ট যেহেতু পাইথনের কাছে isঅপেক্ষাকৃত পরিচয়কে মান তুলনা থেকে আলাদা করতে অপারেটর রয়েছে ।
সিঙ্গেলাইজেশন ইলিমিনেশন

5
আমি মনে করি গৃহীত উত্তরটি সংশোধন করা হবে বা আলগোরিয়াসের উত্তরে পুনরায় নিয়োগ দেওয়া হবে, যাতে কঠোর প্রকারের চেক প্রয়োগ করা হয়।
সর্বোচ্চ

1
এছাড়াও নিশ্চিত হ্যাশ উপেক্ষা করা হয় stackoverflow.com/questions/1608842/...
অ্যালেক্স Punnen

উত্তর:


328

এই সাধারণ সমস্যাটি বিবেচনা করুন:

class Number:

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


n1 = Number(1)
n2 = Number(1)

n1 == n2 # False -- oops

সুতরাং, পাইথন ডিফল্টরূপে তুলনা ক্রিয়াকলাপের জন্য অবজেক্ট শনাক্তকারী ব্যবহার করে:

id(n1) # 140400634555856
id(n2) # 140400634555920

__eq__ফাংশনটি ওভাররাইড করা সমস্যার সমাধান বলে মনে হচ্ছে:

def __eq__(self, other):
    """Overrides the default implementation"""
    if isinstance(other, Number):
        return self.number == other.number
    return False


n1 == n2 # True
n1 != n2 # True in Python 2 -- oops, False in Python 3

ইন পাইথন 2 , সবসময় ওভাররাইড মনে রাখবেন __ne__পাশাপাশি ফাংশন, যেমন ডকুমেন্টেশন পদ বলে:

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

def __ne__(self, other):
    """Overrides the default implementation (unnecessary in Python 3)"""
    return not self.__eq__(other)


n1 == n2 # True
n1 != n2 # False

ইন পাইথন 3 , এই আর প্রয়োজনীয়, যেমন ডকুমেন্টেশন পদ বলে:

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

কিন্তু এটি আমাদের সমস্ত সমস্যার সমাধান করে না। একটি সাবক্লাস যুক্ত করা যাক:

class SubNumber(Number):
    pass


n3 = SubNumber(1)

n1 == n3 # False for classic-style classes -- oops, True for new-style classes
n3 == n1 # True
n1 != n3 # True for classic-style classes -- oops, False for new-style classes
n3 != n1 # False

দ্রষ্টব্য: পাইথন 2 এর দুটি ধরণের ক্লাস রয়েছে:

  • ক্লাসিক-শৈলী (বা পুরাতন-শৈলী ) ক্লাস, যাউত্তরাধিকার সূত্রে প্রাপ্ত হয় নাobject এবং যা হিসাবে ঘোষিত হয়class A:,class A():বাক্লাসিক-শৈলীর শ্রেণিclass A(B):কোথায়B;

  • নতুন স্টাইলের ক্লাসগুলি, যেগুলি উত্তরাধিকার সূত্রে প্রাপ্ত হয়objectএবং যা হিসাবে ঘোষণা করা হয়class A(object)বাclass A(B):যেখানেBএকটি নতুন শৈলীর শ্রেণি রয়েছে। পাইথন 3-এ কেবলমাত্র নতুন-স্টাইলের ক্লাস রয়েছে যা হিসাবে ঘোষণা করা হয়েছেclass A:,class A(object):বাclass A(B):

ক্লাসিক-স্টাইলের ক্লাসগুলির জন্য, একটি তুলনা অপারেশন সর্বদা প্রথম অপারেন্ডের পদ্ধতিটিকে কল করে, যখন নতুন ধাঁচের ক্লাসগুলির জন্য, এটি সর্বদা সাবক্লাস অপারেন্ডের পদ্ধতিটিকে কল করে, অপারেণ্ডগুলির ক্রম নির্বিশেষে

সুতরাং এখানে, যদি Numberএকটি ক্লাসিক-শৈলী শ্রেণি হয়:

  • n1 == n3কল n1.__eq__;
  • n3 == n1কল n3.__eq__;
  • n1 != n3কল n1.__ne__;
  • n3 != n1কল n3.__ne__

এবং যদি Numberএকটি নতুন-শৈলীর শ্রেণি হয়:

  • উভয় n1 == n3এবং n3 == n1কল n3.__eq__;
  • উভয় n1 != n3এবং n3 != n1কল n3.__ne__

পাইথন 2 ক্লাসিক-শৈলীর ক্লাসগুলির জন্য অপারেটরগুলির ==এবং !=অপারেটরগুলির নন-কমিউটিটিভিটি ইস্যুটি ঠিক করার জন্য, যখন অপারেন্ড টাইপ সমর্থিত না হয় তখন __eq__এবং __ne__পদ্ধতিগুলি NotImplementedমানটি ফিরিয়ে দেয় । ডকুমেন্টেশন সংজ্ঞায়িত NotImplementedহিসাবে মান:

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

এই ক্ষেত্রে অপারেটর প্রতিনিধিদের তুলনায় অপারেশন প্রতিফলিত পদ্ধতি এর অন্যান্য অপার্যান্ড। ডকুমেন্টেশন সংজ্ঞায়িত হিসাবে প্রতিফলিত পদ্ধতি:

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

ফলাফলটি এরকম দেখাচ্ছে:

def __eq__(self, other):
    """Overrides the default implementation"""
    if isinstance(other, Number):
        return self.number == other.number
    return NotImplemented

def __ne__(self, other):
    """Overrides the default implementation (unnecessary in Python 3)"""
    x = self.__eq__(other)
    if x is NotImplemented:
        return NotImplemented
    return not x

রিটার্নিং NotImplementedপরিবর্তে মান Falseযদি নতুন স্টাইলের শ্রেণীর এমনকি করতে ডান জিনিস commutativity এর ==এবং !=অপারেটরদের যখন operands সম্পর্কহীন ধরনের (কোন উত্তরাধিকার) হয় আকাঙ্ক্ষিত হয়।

আমরা কি এখনও সেখানে আছি? বেশ না। আমাদের কত অনন্য নম্বর আছে?

len(set([n1, n2, n3])) # 3 -- oops

সেটগুলি অবজেক্টের হ্যাশ ব্যবহার করে এবং ডিফল্টরূপে পাইথন বস্তুর সনাক্তকারীটির হ্যাশ দেয় returns আসুন এটি ওভাররাইড করার চেষ্টা করুন:

def __hash__(self):
    """Overrides the default implementation"""
    return hash(tuple(sorted(self.__dict__.items())))

len(set([n1, n2, n3])) # 1

শেষ ফলাফলটি দেখতে দেখতে (বৈধতার জন্য আমি শেষে কিছু যুক্তি যুক্ত করেছি):

class Number:

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

    def __eq__(self, other):
        """Overrides the default implementation"""
        if isinstance(other, Number):
            return self.number == other.number
        return NotImplemented

    def __ne__(self, other):
        """Overrides the default implementation (unnecessary in Python 3)"""
        x = self.__eq__(other)
        if x is not NotImplemented:
            return not x
        return NotImplemented

    def __hash__(self):
        """Overrides the default implementation"""
        return hash(tuple(sorted(self.__dict__.items())))


class SubNumber(Number):
    pass


n1 = Number(1)
n2 = Number(1)
n3 = SubNumber(1)
n4 = SubNumber(4)

assert n1 == n2
assert n2 == n1
assert not n1 != n2
assert not n2 != n1

assert n1 == n3
assert n3 == n1
assert not n1 != n3
assert not n3 != n1

assert not n1 == n4
assert not n4 == n1
assert n1 != n4
assert n4 != n1

assert len(set([n1, n2, n3, ])) == 1
assert len(set([n1, n2, n3, n4])) == 2

3
hash(tuple(sorted(self.__dict__.items())))মানগুলির মধ্যে যদি কোনও অ-হাঁশযোগ্য বস্তু থাকে তবে কাজ করবে না self.__dict__(অর্থাত্, যদি কোনও বস্তুর কোনও বৈশিষ্ট্য সেট করে বলা হয়, বলুন তবে list)।
সর্বাধিক

3
সত্য, তবে তারপরে যদি আপনার ভারে এ জাতীয় পরিবর্তনযোগ্য বস্তু থাকে () দুটি বস্তু সত্যই সমান নয় ...
তাল ওয়েইস

12
দুর্দান্ত সংক্ষিপ্তসার, তবে এর পরিবর্তে আপনার প্রয়োগ __ne__করা উচিত==__eq__
ফ্লোরিয়ান ব্রুকার

1
তিনটি মন্তব্য: ১. পাইথন 3-তে, __ne__আর প্রয়োগ করার দরকার নেই: "ডিফল্টরূপে, __ne__()প্রতিনিধিরা প্রতিনিধিত্ব করে __eq__()এবং ফলাফলটি উল্টে না দেয় যদি না হয় NotImplemented"। 2. এক এখনো বাস্তবায়ন করতে চায় __ne__, আরো জেনেরিক বাস্তবায়ন (পাইথন 3 আমি মনে করি এর দ্বারা ব্যবহৃত এক) হল: x = self.__eq__(other); if x is NotImplemented: return x; else: return not x। ৩. প্রদত্ত __eq__এবং __ne__বাস্তবায়নগুলি সাবঅপটিমাল: if isinstance(other, type(self)):22 __eq__এবং 10 __ne__কল দেয় , যখন if isinstance(self, type(other)):16 __eq__এবং 6 টি __ne__কল দেয়।
ম্যাগগিরো

4
তিনি কমনীয়তা সম্পর্কে জিজ্ঞাসা, কিন্তু তিনি শক্তিশালী পেয়েছিলাম।
গ্রেগন্যাশ

201

উত্তরাধিকার সম্পর্কে আপনার যত্নবান হওয়া দরকার:

>>> class Foo:
    def __eq__(self, other):
        if isinstance(other, self.__class__):
            return self.__dict__ == other.__dict__
        else:
            return False

>>> class Bar(Foo):pass

>>> b = Bar()
>>> f = Foo()
>>> f == b
True
>>> b == f
False

আরও কঠোরভাবে প্রকার পরীক্ষা করুন:

def __eq__(self, other):
    if type(other) is type(self):
        return self.__dict__ == other.__dict__
    return False

তদ্ব্যতীত, আপনার পদ্ধতির সূক্ষ্মভাবে কাজ করবে, এটি বিশেষ পদ্ধতিগুলির জন্য রয়েছে।


এটি একটি ভালো দিক. আমি মনে করি এটি লক্ষণীয় যে প্রকারভেদে নির্মিত সাব-শ্রেণিবদ্ধতা এখনও সাম্যকে উভয় দিকের জন্য অনুমতি দেয় এবং তাই এটি একই ধরণের পরীক্ষা করাও অযাচিত হতে পারে।
21

12
আমি প্রকারভেদগুলি আরএইচএসের সাথে তুলনা করে, প্রকারগুলি পৃথক হলে নোটইম্প্লিমেন্টেড ফিরে আসার পরামর্শ দেব।
সর্বাধিক

4
@ ম্যাক্সের তুলনা অগত্যা বাম হাতের (এলএইচএস) থেকে ডান হাতের (আরএইচএস), তারপরে আরএইচএস থেকে এলএইচএসে করা হয় না; দেখতে stackoverflow.com/a/12984987/38140 । তবুও, NotImplementedআপনার পরামর্শ অনুসারে প্রত্যাবর্তন সর্বদা কারণ হিসাবে দেখাবে superclass.__eq__(subclass), যা পছন্দসই আচরণ।
গজেনস

4
আপনার যদি টন সদস্য থাকে এবং অনেকগুলি অবজেক্টের অনুলিপি চারপাশে বসে না থাকে তবে প্রাথমিকভাবে পরিচয় পরীক্ষা যুক্ত করা ভাল if other is self। এটি আরও দীর্ঘতর অভিধানের তুলনা এড়িয়ে চলে এবং বস্তুগুলি অভিধান কী হিসাবে ব্যবহার করা হলে একটি বিশাল সঞ্চয় হতে পারে।
ডেন হোয়াইট

2
এবং প্রয়োগ করতে ভুলবেন না__hash__()
ডেন হোয়াইট

161

আপনি যেভাবে বর্ণনা করেছেন তা হ'ল আমি সর্বদা এটি করেছি। যেহেতু এটি সম্পূর্ণ জেনেরিক, আপনি সর্বদা সেই কার্যকারিতাটি মিশ্রণ শ্রেণিতে বিভক্ত করতে পারেন এবং যে ক্লাসে আপনি সেই কার্যকারিতা চান তা উত্তরাধিকার সূত্রে পেতে পারেন।

class CommonEqualityMixin(object):

    def __eq__(self, other):
        return (isinstance(other, self.__class__)
            and self.__dict__ == other.__dict__)

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

class Foo(CommonEqualityMixin):

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

6
+1: সাবক্লাসে সহজে প্রতিস্থাপনের অনুমতি দেওয়ার কৌশল কৌশল pattern
এস। লট

3
ইসিনস্ট্যান্স চুষছে। কেন এটি পরীক্ষা? শুধু স্ব-স্বামী নয় কেন .__ ডিকার__ == অন্যান্য .__ ডক্ট__?
nosklo

3
@ ননস্ক্লো: আমি বুঝতে পারছি না .. যদি সম্পূর্ণ অপ্রাসঙ্গিক শ্রেণীর দুটি বস্তুর একই বৈশিষ্ট্য দেখা দেয় তবে কী হবে?
সর্বোচ্চ

1
আমি ভেবেছিলাম নোকসলো আইসনস্ট্যান্স এড়িয়ে যাওয়ার পরামর্শ দিয়েছেন। সেক্ষেত্রে আপনি আর জানেন না যে otherএকটি সাবক্লাস হয় কিনা self.__class__
সর্বাধিক

10
__dict__তুলনার সাথে আরেকটি বিষয় হ'ল যদি আপনার এমন কোনও বৈশিষ্ট্য থাকে যা আপনি আপনার সমতার সংজ্ঞাতে বিবেচনা করতে চান না (উদাহরণস্বরূপ একটি অনন্য অবজেক্ট আইডি, বা একটি সময় তৈরি স্ট্যাম্পের মতো মেটাডেটা) বলুন।
অ্যাডাম পার্কিন 21

14

সরাসরি উত্তর নয় তবে এটি যথাযথ বলে মনে হচ্ছে এটি উপলক্ষে কিছুটা ভার্বোজ টেডিয়াম সংরক্ষণ করে। ডক্স থেকে সরাসরি কাটা ...


functools.total_ordering (CLS)

এক বা একাধিক সমৃদ্ধ তুলনা ক্রম পদ্ধতিগুলি সংজ্ঞায়িত করে একটি শ্রেণীর দেওয়া, এই শ্রেণীর সাজসজ্জাটি বাকী সরবরাহ করে। এটি সম্ভাব্য সমৃদ্ধ তুলনামূলক ক্রিয়াকলাপগুলির সমস্ত উল্লেখ করার সাথে জড়িত প্রচেষ্টাটিকে সহজতর করে:

ক্লাসের এক সংজ্ঞায়িত করতে হবে __lt__(), __le__(), __gt__(), অথবা __ge__()। এছাড়াও, শ্রেণীর একটি __eq__()পদ্ধতি সরবরাহ করা উচিত ।

সংস্করণ 2.7 এ নতুন

@total_ordering
class Student:
    def __eq__(self, other):
        return ((self.lastname.lower(), self.firstname.lower()) ==
                (other.lastname.lower(), other.firstname.lower()))
    def __lt__(self, other):
        return ((self.lastname.lower(), self.firstname.lower()) <
                (other.lastname.lower(), other.firstname.lower()))

1
তবে মোট_অর্ডারিংয়ের সূক্ষ্ম সমস্যা রয়েছে: regebro.wordpress.com/2010/12/13/… । সচেতন থাকা !
মিস্টার_আর_আমস_ডি

8

আপনাকে উভয়ই ওভাররাইড করতে হবে না __eq__এবং __ne__আপনি কেবল ওভাররাইড করতে পারেন __cmp__তবে এটি ==,! ==, <,> এবং এর ফলাফলের উপর জড়িত হয়ে উঠবে।

isবস্তু সনাক্তকরণের জন্য পরীক্ষা। এর অর্থ একটি isখ তখন ঘটবে Trueযখন ক এবং খ উভয় একই বস্তুর রেফারেন্স ধরে রাখবে। অজগরতে আপনি সর্বদা কোনও আসল বস্তুর পরিবর্তে কোনও ভেরিয়েবলের একটি রেফারেন্স রাখেন, সুতরাং মূলত a খ এর সত্য হওয়াতে তাদের মধ্যে থাকা বস্তুগুলি একই মেমরির স্থানে অবস্থিত হওয়া উচিত। আপনি কীভাবে এবং সর্বাধিক গুরুত্বপূর্ণ কেন এই আচরণটি অগ্রাহ্য করবেন?

সম্পাদনা: আমি জানি না __cmp__অজগর 3 থেকে অপসারণ করা হয়েছে তাই এটি এড়িয়ে চলুন।


কারণ কখনও কখনও আপনার জিনিসগুলির জন্য সমতার একটি আলাদা সংজ্ঞা থাকে।
এড এস।

অপারেটর আপনি বস্তুর পরিচয় দোভাষী উত্তর দেয়, কিন্তু আপনি এখনও আপনার অগ্রাহ্য দ্বারা সমতা মানচিত্র দর্শনে প্রকাশ করার মুক্ত CMP
Vasil

7
পাইথন 3-এ, "সিএমপি () ফাংশনটি শেষ হয়ে গেছে এবং __cmp __ () বিশেষ পদ্ধতি আর সমর্থিত নয়।" is.gd/aeGv
23:50

4

এই উত্তর থেকে: https://stackoverflow.com/a/30676267/541136 আমি প্রমাণ করে দিয়েছি, যদিও এটি __ne__শর্তাবলী সংজ্ঞায়িত করা সঠিক __eq__- পরিবর্তে

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

আপনার ব্যবহার করা উচিত:

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

2

আমি মনে করি যে আপনি যে দুটি পদ সন্ধান করছেন তা হ'ল সমতা (==) এবং পরিচয় (যা)। উদাহরণ স্বরূপ:

>>> a = [1,2,3]
>>> b = [1,2,3]
>>> a == b
True       <-- a and b have values which are equal
>>> a is b
False      <-- a and b are not the same list object

1
হতে পারে, এটি বাদ দিয়ে যে কোনও শ্রেণি তৈরি করতে পারে যা কেবল দুটি তালিকার মধ্যে প্রথম দুটি আইটেমের তুলনা করে, এবং যদি সেই আইটেমগুলি সমান হয়, তবে এটি সত্যের সাথে মূল্যায়ন করে। এটি সমতা, আমি মনে করি, সাম্য নয়। পুরোপুরি বৈধ EQ , এখনও।
23-08 এ গেজেসন

তবে আমি সম্মত হই না যে "" হ'ল একটি পরিচয়ের একটি পরীক্ষা।
23-08 এ গিগেনেস

1

'বিল্ডিন' আইডি () 'ফাংশনটি ব্যবহার করে সনাক্তকরণের জন্য' এটি 'পরীক্ষাটি পরীক্ষা করবে যা মূলত অবজেক্টটির মেমরি ঠিকানা ফেরত দেয় এবং অতএব ওভারলোডযোগ্য নয়।

তবে কোনও শ্রেণির সাম্যতা পরীক্ষা করার ক্ষেত্রে আপনি সম্ভবত আপনার পরীক্ষাগুলি সম্পর্কে কিছুটা আরও কঠোর হতে চান এবং কেবল আপনার শ্রেণীর ডেটা অ্যাট্রিবিউটগুলির সাথে তুলনা করতে পারেন:

import types

class ComparesNicely(object):

    def __eq__(self, other):
        for key, value in self.__dict__.iteritems():
            if (isinstance(value, types.FunctionType) or 
                    key.startswith("__")):
                continue

            if key not in other.__dict__:
                return False

            if other.__dict__[key] != value:
                return False

         return True

এই কোডটি কেবল আপনার শ্রেণীর নন ফাংশন ডেটার সদস্যদের পাশাপাশি ব্যক্তিগত কোনও কিছু বাদ দেওয়ার সাথে সাথে তুলনা করবে যা সাধারণত আপনি চান। সরল পুরাতন পাইথন অবজেক্টের ক্ষেত্রে আমার একটি বেস ক্লাস রয়েছে যা __init__, __str__, __repr__ এবং __eq__ প্রয়োগ করে যাতে আমার POPO অবজেক্টগুলি অতিরিক্ত (এবং বেশিরভাগ ক্ষেত্রে অভিন্ন) যুক্তিটির বোঝা বহন করে না।


বিট নিতপিকি, তবে আইডি () ব্যবহার করে পরীক্ষাগুলি কেবলমাত্র যদি আপনি নিজের নিজস্ব__ () সদস্য ফাংশন (2.3+) সংজ্ঞায়িত না করেন। [ docs.python.org/library/operator.html]
স্পেনথিল

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

mcrute - আমি খুব শীঘ্রই কথা বলেছি (এবং ভুলভাবে), আপনি একেবারে ঠিক বলেছেন।
স্পেনথিল

এটি খুব সুন্দর সমাধান, বিশেষত যখন __eq__ঘোষণা করা হবে CommonEqualityMixin(অন্য উত্তরটি দেখুন)। এসকিউএলএলচেমির বেস থেকে প্রাপ্ত ক্লাসগুলির উদাহরণগুলির সাথে তুলনা করার সময় আমি এটি বিশেষভাবে দরকারী বলে মনে করি। তুলনা না করার জন্য _sa_instance_stateআমি পরিবর্তিত key.startswith("__")):হয়েছে key.startswith("_")):। এগুলিতে আমার কিছুটা পিছনেও ছিল এবং আলগোরিয়াসের উত্তর অন্তহীন পুনরাবৃত্তি ঘটায়। সুতরাং আমি সমস্ত ব্যাকেরিফারেন্সের নাম দিয়ে শুরু করেছি '_'যাতে তারা তুলনার সময় এড়িয়ে যায়। দ্রষ্টব্য: পাইথন 3.x এ পরিবর্তন iteritems()করুন items()
Wookie88

@ এমক্রুট সাধারণত: __dict__উদাহরণস্বরূপ এমন কোনও কিছুই থাকে না যা __এটির দ্বারা ব্যবহারকারী দ্বারা সংজ্ঞায়িত না করা থাকে with ভীষণ পছন্দ __class__, __init__ইত্যাদি উদাহরণস্বরূপ এর মধ্যে নেই __dict__, বরং তার বর্গ ' __dict__। OTOH, ব্যক্তিগত বৈশিষ্ট্যগুলি সহজেই শুরু __হতে পারে এবং সম্ভবত এটির জন্য ব্যবহার করা উচিত __eq____পূর্বনির্ধারিত বৈশিষ্ট্যগুলি এড়িয়ে যাওয়ার সময় আপনি ঠিক কী এড়াতে চাইছিলেন তা আপনি পরিষ্কার করতে পারেন ?
সর্বোচ্চ

1

সাবক্লাসিং / মিক্সিন ব্যবহার করার পরিবর্তে, আমি জেনেরিক ক্লাস ডেকরেটার ব্যবহার করতে পছন্দ করি

def comparable(cls):
    """ Class decorator providing generic comparison functionality """

    def __eq__(self, other):
        return isinstance(other, self.__class__) and self.__dict__ == other.__dict__

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

    cls.__eq__ = __eq__
    cls.__ne__ = __ne__
    return cls

ব্যবহার:

@comparable
class Number(object):
    def __init__(self, x):
        self.x = x

a = Number(1)
b = Number(1)
assert a == b

0

এটি আলগোরিয়াসের উত্তরের মন্তব্যগুলিকে অন্তর্ভুক্ত করে এবং একটি একক বৈশিষ্ট্যের দ্বারা অবজেক্টের তুলনা করে কারণ আমি পুরো ডিকের যত্ন নেই। hasattr(other, "id")অবশ্যই সত্য হতে হবে, তবে আমি জানি এটি কারণ কারণ আমি এটি কনস্ট্রাক্টরে রেখেছি।

def __eq__(self, other):
    if other is self:
        return True

    if type(other) is not type(self):
        # delegate to superclass
        return NotImplemented

    return other.id == self.id
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.