__সাম্প__ এর পরিবর্তে______


103

পাইথন ২.x এর তুলনা অপারেটরগুলির ওভারলোডের দুটি উপায় রয়েছে __cmp__বা "সমৃদ্ধ তুলনা অপারেটরগুলি" যেমন __lt__সমৃদ্ধ তুলনা ওভারলোডগুলি অগ্রাধিকার হিসাবে বলা হয়, তবে কেন এটি এমন?

সমৃদ্ধ তুলনা অপারেটরগুলি প্রতিটি বাস্তবায়নের জন্য সহজ, তবে আপনাকে অবশ্যই প্রায় একই রকম যুক্তি দিয়ে তাদের বেশ কয়েকটি বাস্তবায়ন করতে হবে। তবে, আপনি যদি বিল্টিন cmpএবং টুপল অর্ডার ব্যবহার করতে পারেন তবে __cmp__বেশ সহজ হয়ে যায় এবং সমস্ত তুলনা পূরণ করে:

class A(object):
  def __init__(self, name, age, other):
    self.name = name
    self.age = age
    self.other = other
  def __cmp__(self, other):
    assert isinstance(other, A) # assumption for this example
    return cmp((self.name, self.age, self.other),
               (other.name, other.age, other.other))

এই সরলতাটি ধনী তুলনাগুলির সমস্ত 6 (!) ওভারলোডের চেয়ে আমার চাহিদা মেটাচ্ছে বলে মনে হচ্ছে। (যাইহোক, আপনি যদি "অদলবদল যুক্তি" / প্রতিবিম্বিত আচরণের উপর নির্ভর করেন তবে আপনি এটি "ন্যায্য 4" এ নামাতে পারেন, তবে এটি আমার নম্র মতামত হিসাবে জটিলতার জট বাড়িয়েছে))

আমি যদি কেবল ওভারলোড করি তবে আমার কি সচেতন হওয়া দরকার __cmp__?

আমি বুঝতে পারছি <, <=, ==, ইত্যাদি অপারেটার অন্যান্য কাজের জন্য ওভারলোড হতে পারে, এবং মত কোন বস্তু তারা ফিরে আসতে পারেন। আমি সেই পদ্ধতির গুণাগুণ সম্পর্কে জিজ্ঞাসা করছি না, তবে কেবলমাত্র পার্থক্য সম্পর্কে যখন এই অপারেটরগুলি তুলনা করার জন্য একই অর্থে ব্যবহার করে যা তারা সংখ্যার জন্য বোঝায়।

আপডেট: ক্রিস্টোফার যেমনটি বলেছেন , cmp3.x সালে অদৃশ্য হয়ে যাচ্ছে উপরের মতো তুলনামূলক বাস্তবায়নকে কী এমন বিকল্প আছে __cmp__?


5
আপনার শেষ প্রশ্ন পুনরায় আমার উত্তর দেখুন, কিন্তু আসলে সেখানে একটি নকশা যে জিনিস এমনকি পুলিশের সহ অনেক ক্লাস জন্য সহজ করতে হবে (ডান এখন আপনি যদি একটি mixin, ক্লাসের অধীনে একটি ক্লাস, অথবা বর্গ তা কাজে লাগানোর প্রসাধক প্রয়োজন) আছে: যদি কোন কী বিশেষ পদ্ধতি উপস্থিত থাকলে, এটি অবশ্যই মানগুলির একটি দ্বিগুণ ফিরিয়ে আনতে হবে এবং সমস্ত তুলনাকারী এবং হ্যাশটিকে এই টিপলটির ক্ষেত্রে সংজ্ঞায়িত করা হবে। গিডো আমার ধারণাটি তাকে পছন্দ করার সময় পছন্দ করেছিল তবে আমি অন্যান্য বিষয় নিয়ে ব্যস্ত হয়ে পড়েছিলাম এবং কখনও পিইপি লেখার জন্য পাইনি ... সম্ভবত maybe.২ ;-) এর জন্য। এদিকে আমি তার জন্য আমার মেশিনটি ব্যবহার করতে থাকি! -)
অ্যালেক্স মার্টেলি

উত্তর:


93

হ্যাঁ, উদাহরণস্বরূপ __lt__মিক্সিন ক্লাসের সাথে (বা একটি মেটাক্লাস, বা আপনার স্বাদটি যদি এভাবে চালিত হয় তবে কোনও শ্রেণি সজ্জাকারক) সাথে প্রতিটি পদক্ষেপ কার্যকর করা সহজ ।

উদাহরণ স্বরূপ:

class ComparableMixin:
  def __eq__(self, other):
    return not self<other and not other<self
  def __ne__(self, other):
    return self<other or other<self
  def __gt__(self, other):
    return other<self
  def __ge__(self, other):
    return not self<other
  def __le__(self, other):
    return not other<self

এখন আপনার শ্রেণিটি __lt__তুলনামূলক মিক্সিন থেকে সঠিকভাবে সংজ্ঞা দিতে পারে এবং উত্তরাধিকারকে আরও বহুগুণে বাড়িয়ে তুলতে পারে (অন্য যে কোনও বেসগুলির প্রয়োজন পরে, যদি তা হয় তবে)। একটি শ্রেণি সাজসজ্জাটি একই রকম হবে, কেবল নতুন শ্রেণীর সাজসজ্জা হিসাবে এটি একই বৈশিষ্ট্য সন্নিবেশ করানো হবে (স্মৃতি অনুসারে সমান মিনিট ব্যয়ে, রানআমে ফলটি মাইক্রোস্কোপিকভাবে দ্রুততর হতে পারে)।

অবশ্যই, যদি আপনার ক্লাসে কিছু কার্যকর উপায় প্রয়োগ করা হয় (উদাহরণস্বরূপ) __eq__এবং __ne__, এটি সরাসরি তাদের সংজ্ঞায়িত করা উচিত যাতে মিক্সিনের সংস্করণগুলি ব্যবহার না করা হয় (উদাহরণস্বরূপ, এটি ক্ষেত্রে এটি dict) __ne__সুবিধার্থে সুবিধার্থে সংজ্ঞায়িত করা যেতে পারে যে হিসাবে:

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

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

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

আরও সম্পাদনা: আসলে প্রশ্নটির সাথে অনেক শ্রেণীর জন্য তুলনা এবং হ্যাশিং সরবরাহ করার আরও একটি ভাল উপায় আছে - একটি __key__পদ্ধতি, যা আমি প্রশ্নের আমার মন্তব্যে উল্লেখ করেছি। যেহেতু আমি এর জন্য পিইপি লেখার জন্য কখনই আশ্রয় পাই নি, আপনি যদি এটি পছন্দ করেন তবে আপনাকে অবশ্যই এটি বর্তমানে মিক্সিন (& সি) দিয়ে প্রয়োগ করতে হবে:

class KeyedMixin:
  def __lt__(self, other):
    return self.__key__() < other.__key__()
  # and so on for other comparators, as above, plus:
  def __hash__(self):
    return hash(self.__key__())

অন্যান্য ক্ষেত্রগুলির সাথে কয়েকটি ক্ষেত্রের সাথে একটি তুলির তুলনায় অন্যান্য উদাহরণগুলির সাথে উদাহরণের তুলনা করার ক্ষেত্রে এটি খুব সাধারণ ঘটনা - এবং তারপরে হ্যাশিং ঠিক একই ভিত্তিতে প্রয়োগ করা উচিত। __key__বিশেষ পদ্ধতি ঠিকানাগুলি সরাসরি প্রয়োজন।


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

আমি সত্যিই এই মূল ধারণাটি পছন্দ করি , এটি ব্যবহার করতে যাচ্ছি এবং এটি কেমন অনুভূত হয় তা দেখুন। (যদিও সংরক্ষিত নামের পরিবর্তে নাম দেওয়া হয়েছে সিএমপি_কি বা _সিএমপি_কি))

TypeError: Cannot create a consistent method resolution order (MRO) for bases object, ComparableMixinআমি যখন পাইথন 3 এ চেষ্টা করি 3. gist.github.com/2696496
অ্যাডাম পার্কিন

4
পাইথন ২.7 + / / ৩.২ + তে আপনি functools.total_orderingনিজের বিল্ডিংয়ের পরিবর্তে ব্যবহার করতে পারেন ComparableMiximJmagnusson এর উত্তরে
দিন

4
পাইথন 3 এ <প্রয়োগ করতে ব্যবহার করা __eq__বেশ খারাপ ধারণা, কারণ এটি TypeError: unorderable types
অ্যান্টি হাপাল

51

এই কেসটিকে সহজ করার জন্য পাইথন ২.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()))

9
total_ordering__ne__যদিও বাস্তবায়ন করে না , তাই দেখুন!
ফ্লিম

4
@ ফ্লিম, তা হয় না তবে __ne__। তবে এর কারণ __ne__হ'ল ডিফল্ট বাস্তবায়ন যা প্রতিনিধিদের __eq__। তাই এখানে দেখার মতো কিছুই নেই।
জানু হুডেক 21

কমপক্ষে একটি অর্ডারিং অপারেশন অবশ্যই সংজ্ঞায়িত করতে হবে: <> <=> = .... EQ মোট অর্ডার হিসাবে প্রয়োজন হয় না যদি! a <b এবং b <a then a = b
জ্যানলান্টোস

9

এটি পিইপি 207- সমৃদ্ধ তুলনা দ্বারা আচ্ছাদিত

এছাড়াও, __cmp__অজগর 3.0 এ চলে যায়। (দ্রষ্টব্য যে এটি http://docs.python.org/3.0/references/datamodel.html তে উপস্থিত নেই তবে এটি http://docs.python.org/2.7/references/datamodel.html এ রয়েছে )


পিইপি কেবলমাত্র সমৃদ্ধ তুলনা কেন প্রয়োজন তা নিয়েই উদ্বিগ্ন, নুমপাই ব্যবহারকারীরা যেভাবে <বি> একটি ক্রম ফিরে আসতে চান।

আমি বুঝতে পারি নি যে এটি অবশ্যই চলে যাচ্ছে, এটি আমার মন খারাপ করে। (তবে এটি দেখানোর জন্য ধন্যবাদ))

পিইপি তাদের "কেন" পছন্দ করে সে সম্পর্কেও আলোচনা করে। মূলত এটি দক্ষতার দিকে ফোটে: 1. আপনার ক্রিয়াকলাপগুলি কার্যকর করার দরকার নেই যা আপনার অবজেক্টের জন্য কোনও ধারণা রাখে না (আনর্ডার্ড সংগ্রহ হিসাবে)) ধনী তুলনাগুলি যদি আপনি তাদের সংজ্ঞায়িত করেন তবে দোভাষীকে সেটার সুবিধা নিতে দেয়।
ক্রিস্টোফার

4
পুনরায় 1, তারা যদি তা বোঝায় না, তবে সিএমপি বাস্তবায়ন করবেন না । পুনরায় 2, উভয় বিকল্প থাকা আপনার প্রয়োজন অনুসারে অপ্টিমাইজ করতে দেয়, তবুও দ্রুত প্রোটোটাইপিং এবং পরীক্ষা করে। এটি কেন সরানো হয়েছে তা কেউই আমাকে বলে না। (মূলত এটি আমার জন্য বিকাশকারীর দক্ষতায় ফোটে)) সিএমপি ফালব্যাকের জায়গায় সমৃদ্ধ তুলনাগুলি কি কম দক্ষ ? এটা আমার কাছে বোধগম্য হবে না।

4
@ আর। পেট, যেমন আমি আমার উত্তরে ব্যাখ্যা করার চেষ্টা করেছি, সাধারণতার কোনও আসল ক্ষতি নেই (যেহেতু একটি মিশ্রণ, সাজসজ্জাকারী বা মেটাক্লাস, আপনাকে কেবলমাত্র <যদি আপনি চান) এর দিক দিয়ে সমস্ত কিছু সংজ্ঞায়িত করতে দেয় এবং তাই সমস্ত পাইথন বাস্তবায়নকে ঘিরে রাখার জন্য অনর্থক কোডটি চিরতরে সিএমপিতে ফিরে আসবে - পাইথন ব্যবহারকারীদের দুটি সমতুল্য উপায়ে জিনিস প্রকাশ করতে দেওয়া - পাইথনের শস্যের বিরুদ্ধে 100% চলবে would
অ্যালেক্স মার্টেলি

3

(মন্তব্যগুলি আমলে নিতে 6/17/17 সম্পাদিত)

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


class ComparableMixin(object):

    def __eq__(self, other):
        if not isinstance(other, type(self)): 
            return NotImplemented
        else:
            return not self<other and not other<self

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

    def __gt__(self, other):
        if not isinstance(other, type(self)): 
            return NotImplemented
        else:
            return other<self

    def __ge__(self, other):
        if not isinstance(other, type(self)): 
            return NotImplemented
        else:
            return not self<other

    def __le__(self, other):
        if not isinstance(other, type(self)): 
            return NotImplemented
        else:
            return not other<self    

আপনি কিভাবে মনে করেন যে, না selfSingleton হতে পারে Noneএর NoneTypeএবং একই সময়ে আপনার বাস্তবায়ন ComparableMixin? আর এই রেসিপি পাইথন 3. জন্য খারাপ
Antti Haapala

4
selfহবে না হবে None, যাতে শাখা সম্পূর্ণভাবে যেতে পারেন। ব্যবহার করবেন না type(other) == type(None); সহজভাবে ব্যবহার other is None। বরং বিশেষ-বা ছোট হাতের অক্ষর চেয়ে Noneপরীক্ষার হলে অন্য ধরনের ধরনের একটি দৃষ্টান্ত হল self, এবং আসতে NotImplementedSingleton যদি না: if not isinstance(other, type(self)): return NotImplemented। সমস্ত পদ্ধতির জন্য এটি করুন। পাইথন এর পরে অন্য অপারেন্ডকে পরিবর্তে উত্তর দেওয়ার সুযোগ দিতে পারে।
মার্টিজন পিটারস

1

অ্যালেক্স Martelli এর দ্বারা অনুপ্রাণিত ComparableMixinKeyedMixinউত্তর, আমি নিম্নলিখিত mixin নিয়ে এসেছেন। এটি আপনাকে একটি একক _compare_to()পদ্ধতি প্রয়োগ করতে সহায়তা করে , যা কী-ভিত্তিক তুলনাগুলি অনুরূপ ব্যবহার করে KeyedMixin, তবে আপনার শ্রেণীর প্রকারের ভিত্তিতে সবচেয়ে দক্ষ তুলনা কী বাছাই করতে দেয় other। (দ্রষ্টব্য যে এই মিশ্রণটি বস্তুগুলির পক্ষে খুব বেশি সহায়তা করে না যা আদেশের জন্য নয় বরং সাম্যের জন্য পরীক্ষা করা যেতে পারে)।

class ComparableMixin(object):
    """mixin which implements rich comparison operators in terms of a single _compare_to() helper"""

    def _compare_to(self, other):
        """return keys to compare self to other.

        if self and other are comparable, this function 
        should return ``(self key, other key)``.
        if they aren't, it should return ``None`` instead.
        """
        raise NotImplementedError("_compare_to() must be implemented by subclass")

    def __eq__(self, other):
        keys = self._compare_to(other)
        return keys[0] == keys[1] if keys else NotImplemented

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

    def __lt__(self, other):
        keys = self._compare_to(other)
        return keys[0] < keys[1] if keys else NotImplemented

    def __le__(self, other):
        keys = self._compare_to(other)
        return keys[0] <= keys[1] if keys else NotImplemented

    def __gt__(self, other):
        keys = self._compare_to(other)
        return keys[0] > keys[1] if keys else NotImplemented

    def __ge__(self, other):
        keys = self._compare_to(other)
        return keys[0] >= keys[1] if keys else NotImplemented
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.