অভিধান কী হিসাবে কাস্টম প্রকারের অবজেক্ট


185

পাইথন অভিধানে কী (যেমন আমি "অবজেক্ট আইডি" কী হিসাবে কাজ করতে চাই না) কী হিসাবে কাস্টম ধরণের আমার অবজেক্টগুলি ব্যবহার করতে আমার কী করতে হবে, উদাহরণস্বরূপ

class MyThing:
    def __init__(self,name,location,length):
            self.name = name
            self.location = location
            self.length = length

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

এটি সম্পাদন করার জন্য পাইথনে আমার কী করা উচিত? আমারও কি উচিত?

(একটি সাধারণ ক্ষেত্রে, যেমন এখানে, সম্ভবত একটি (নাম, অবস্থান) টিপলকে কী হিসাবে রাখাই ভাল হবে - তবে বিবেচনা করুন আমি কীটি কোনও বস্তু হতে চাই)


হ্যাশ ব্যবহার করে কী দোষ হয়েছে?
রাফে কেটলার

5
সম্ভবত কারণ তিনি দুটি চান MyThing, যদি তাদের দুটি একই থাকে nameএবং locationঅভিধানটি একই মান ফেরত দিতে সূচীকরণ করতে, যদিও সেগুলি দুটি পৃথক দুটি "বস্তু" হিসাবে পৃথকভাবে তৈরি করা হয়েছিল।
সান্তা

1
"সম্ভবত একটি (নাম, অবস্থান) টিপলটিকে কী হিসাবে রাখলে ভাল হবে - তবে কীটিটি একটি বস্তু হতে চাই তা বিবেচনা করুন)" আপনার অর্থ: কোনও নন-কম্পোজিট অবজেক্ট?
আইকোম

উত্তর:


219

আপনাকে 2 টি পদ্ধতি যুক্ত করতে হবে , নোট __hash__এবং __eq__:

class MyThing:
    def __init__(self,name,location,length):
        self.name = name
        self.location = location
        self.length = length

    def __hash__(self):
        return hash((self.name, self.location))

    def __eq__(self, other):
        return (self.name, self.location) == (other.name, other.location)

    def __ne__(self, other):
        # Not strictly necessary, but to avoid having both x==y and x!=y
        # True at the same time
        return not(self == other)

পাইথন ডকের ডকুমেন্টেশনগুলি এই প্রয়োজনীয়তাগুলি মূল বিষয়গুলিতে সংজ্ঞায়িত করে, অর্থাত্ তাদের অবশ্যই প্রাপ্য হতে পারে ।


17
hash(self.name)দেখতে আরও সুন্দর লাগে self.name.__hash__(), এবং যদি আপনি নিজে করেন এবং আপনি hash((x, y))নিজেকে এক্সওরিং এড়ানোর জন্য করতে পারেন ।
রোশ অক্সিমারন

5
অতিরিক্ত নোট হিসাবে, আমি কেবল আবিষ্কার করেছি যে এর x.__hash__()মতো কল করাও ভুল , কারণ এটি ভুল ফলাফল তৈরি করতে পারে : পেস্টবিন.
com/সি

@ রশ অক্সিমারন: মন্তব্যের জন্য আপনাকে ধন্যবাদ। লেখার সময় আমি ব্যবহার সুনিদৃষ্ট andজন্য __eq__আমি ভেবেছিলাম কিন্তু তারপর "কেন tuples ব্যবহার করছেন না?" কারণ আমি প্রায়শই যাইহোক এটি করি (আমি মনে করি এটি আরও পাঠযোগ্য)। কিছু অদ্ভুত কারণে আমার চোখের প্রশ্ন সম্পর্কে __hash__কিন্তু ফিরে যান না ।
6502

1
@ ইউজার 737329৩29২: আপনি কি কিছু ব্লেন্ডার ডেটা স্ট্রাকচার কী হিসাবে ব্যবহার করার চেষ্টা করছেন? দৃশ্যত কিছু ভাণ্ডার থেকে কিছু নির্দিষ্ট অবজেক্টের পরিবর্তনের জন্য আপনাকে এগুলিকে প্রথমে "হিমায়িত" করতে হবে (পাইথন অভিধানে মূল হিসাবে ব্যবহৃত একটি মান-ভিত্তিক অবজেক্টের অনুমতি দেওয়া হয়নি)
6502

1
@ kawing-Chiu pythonfiddle.com/eq-method-needs-ne-method <- এই শো "বাগ" পাইথন 2. পাইথন 3 এই সমস্যা নেই : ডিফল্ট __ne__()হয়েছে "fixed"
বব স্টেইন

34

পাইথন ২.6 বা তারও উপরে একটি বিকল্প ব্যবহার করা collections.namedtuple()- এটি আপনাকে কোনও বিশেষ পদ্ধতি লেখার জন্য সংরক্ষণ করে:

from collections import namedtuple
MyThingBase = namedtuple("MyThingBase", ["name", "location"])
class MyThing(MyThingBase):
    def __new__(cls, name, location, length):
        obj = MyThingBase.__new__(cls, name, location)
        obj.length = length
        return obj

a = MyThing("a", "here", 10)
b = MyThing("a", "here", 20)
c = MyThing("c", "there", 10)
a == b
# True
hash(a) == hash(b)
# True
a == c
# False

20

আপনি __hash__যদি বিশেষ হ্যাশ-শব্দার্থবিজ্ঞান চান এবং __cmp__বা __eq__আপনার শ্রেণিটিকে কী হিসাবে ব্যবহারযোগ্য করে তুলতে চান তবে আপনি ওভাররাইড করুন । যেসব বস্তু সমান তুলনা করে তাদের একই হ্যাশ মান হওয়া দরকার।

পাইথন প্রত্যাশা করে __hash__যে কোনও পূর্ণসংখ্যা ফেরত দেয়, ফিরে আসার Banana()প্রস্তাব দেওয়া হয় না :)

ব্যবহারকারীর সংজ্ঞায়িত ক্লাসগুলির __hash__ডিফল্টরূপে কল রয়েছে id(self), যেমন আপনি উল্লেখ করেছেন।

ডকুমেন্টেশন থেকে কিছু অতিরিক্ত টিপস রয়েছে :

যে ক্লাসগুলি __hash__() পিতামাত্ত শ্রেণীর কাছ থেকে কোনও পদ্ধতি উত্তরাধিকার সূত্রে প্রাপ্ত হয় তবে এর অর্থ __cmp__()বা এর পরিবর্তিত __eq__() হ্যাশ মানটি আর উপযুক্ত হয় না (উদাহরণস্বরূপ ডিফল্ট পরিচয় ভিত্তিক সাম্যতার পরিবর্তে সাম্যের মান-ভিত্তিক ধারণায় স্যুইচ করে) স্পষ্টভাবে তাদেরকে পতাকা হিসাবে চিহ্নিত করতে পারে __hash__ = None ক্লাস সংজ্ঞা সেট করে অদৃশ্য হওয়া । এটি করার অর্থ হ'ল ক্লাসের উদাহরণগুলি কেবল একটি উপযুক্ত টাইপরর বাড়িয়ে তুলবে না যখন কোনও প্রোগ্রাম তাদের হ্যাশ মানটি পুনরুদ্ধার করার চেষ্টা করবে, তবে চেক করার সময় এগুলি যথাযথভাবে অপসারণযোগ্য হিসাবে চিহ্নিত হবে isinstance(obj, collections.Hashable) ( স্পষ্টতই টাইপরর __hash__()বাড়াতে তাদের নিজস্ব সংজ্ঞাযুক্ত শ্রেণীর বিপরীতে )।


2
হ্যাশ একা যথেষ্ট নয়, অতিরিক্তভাবে আপনাকে হয় ওভাররাইড করতে হবে __eq__বা __cmp__
ওবেন সোন

@ ওবেন সোন: __cmp__এটি ব্যবহারকারীর সংজ্ঞায়িত শ্রেণি হলে পাইথন আপনাকে দেওয়া হয়, তবে আপনি সম্ভবত নতুন শব্দার্থবিজ্ঞানের জন্য উপযুক্তভাবে সেগুলি ওভাররাইড করতে চান।
Skurmedel

1
@ স্কুরমিডেল: হ্যাঁ, তবে আপনি যদি এই ক্লাসগুলিকে ওভাররাইড না করে এমন ব্যবহারকারী ক্লাসগুলিতে কল করতে cmpএবং ব্যবহার করতে পারেন =তবে প্রশ্নকারীর প্রয়োজনীয়তা মেটাতে তাদের একটি অবশ্যই প্রয়োগ করতে হবে যে অনুরূপ নাম এবং অবস্থানের উদাহরণগুলির ক্ষেত্রে একই অভিধান কী রয়েছে।
ওবেন সোন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.