কীভাবে সঠিকভাবে সাবক্লাস ডিক এবং ওভাররাইড করুন __getitem__ এবং __setitem__


84

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

class DictWatch(dict):
    def __init__(self, *args):
        dict.__init__(self, args)

    def __getitem__(self, key):
        val = dict.__getitem__(self, key)
        log.info("GET %s['%s'] = %s" % str(dict.get(self, 'name_label')), str(key), str(val)))
        return val

    def __setitem__(self, key, val):
        log.info("SET %s['%s'] = %s" % str(dict.get(self, 'name_label')), str(key), str(val)))
        dict.__setitem__(self, key, val)

' name_label'একটি কী যা শেষ পর্যন্ত সেট করা হবে যা আমি আউটপুট সনাক্ত করতে ব্যবহার করতে চাই। তারপরে আমি সাবক্লাসের DictWatchপরিবর্তে সাবস্ক্লাসে চালিত ক্লাসটি dictপরিবর্তিত করেছি এবং কলটি সুপার কনস্ট্রাক্টরের কাছে পরিবর্তন করেছি। তবুও, কিছুই ঘটছে বলে মনে হচ্ছে না। আমি ভেবেছিলাম আমি চালাক হয়ে যাচ্ছি, তবে আমি ভাবছি যে আমার কোনও অন্য দিকে যেতে হবে কিনা।

সাহায্যের জন্য ধন্যবাদ!


আপনি লগ পরিবর্তে মুদ্রণ ব্যবহার করার চেষ্টা করেছেন? এছাড়াও, আপনি কীভাবে আপনার লগ তৈরি / কনফিগার করবেন তা ব্যাখ্যা করতে পারেন?
pajton

4
dict.__init__নেয় না *args?
টম রাসেল

4
সাজসজ্জার জন্য বেশ ভালো প্রার্থীর মতো দেখতে লাগে।
টম রাসেল

উত্তর:


39

আপনি যা করছেন তা একেবারে কাজ করা উচিত। আমি আপনার ক্লাসটি পরীক্ষা করেছি এবং আপনার লগের বিবৃতিগুলিতে একটি অনুপস্থিত খোলার প্রথম বন্ধনীর বাইরে, এটি ঠিক কাজ করে। আমি ভাবতে পারি মাত্র দুটি বিষয়। প্রথমত, আপনার লগ স্টেটমেন্টের আউটপুটটি সঠিকভাবে সেট করা আছে? logging.basicConfig(level=logging.DEBUG)আপনার স্ক্রিপ্টের শীর্ষে আপনার একটি লাগাতে হবে ।

দ্বিতীয়ত, __getitem__এবং __setitem__কেবল []অ্যাক্সেসের সময় বলা হয় । তাই নিশ্চিত করুন যে আপনি শুধুমাত্র এক্সেস করা DictWatchমাধ্যমে d[key]বদলে d.get()এবংd.set()


প্রকৃতপক্ষে এটি অতিরিক্ত (str(dict.get(self, 'name_label')), str(key), str(val)))
পেরেনগুলি

4
সত্য। ওপিকে: ভবিষ্যতের রেফারেন্সের জন্য, আপনি পাইথন স্ট্রিং ফর্ম্যাটিং অপারেটরের পরিবর্তে কেবল লগ.info ('% s% s% s, a, b, c) করতে পারেন।
BrainCore

লগিং স্তরটি ইস্যু হিসাবে শেষ হয়েছিল। আমি অন্য কারও কোডটি ডিবাগ করছি এবং আমি মূলত অন্য কোনও ফাইলে পরীক্ষা করছিলাম যা ডিবাগিং সেটের বিভিন্ন স্তরের শীর্ষে রয়েছে। ধন্যবাদ!
মাইকেল মায়ার

73

সাবক্লাসিংয়ের সময় আর একটি সমস্যা dictহ'ল বিল্ট-ইন __init__কল করে না update, এবং বিল্ট-ইন updateকল করে না __setitem__। সুতরাং, যদি আপনি চান যে সমস্ত সেটাইটেম অপারেশনগুলি আপনার __setitem__ক্রিয়াকলাপের মধ্য দিয়ে চলেছে , আপনার অবশ্যই এটি নিশ্চিত হওয়া উচিত:

class DictWatch(dict):
    def __init__(self, *args, **kwargs):
        self.update(*args, **kwargs)

    def __getitem__(self, key):
        val = dict.__getitem__(self, key)
        print('GET', key)
        return val

    def __setitem__(self, key, val):
        print('SET', key, val)
        dict.__setitem__(self, key, val)

    def __repr__(self):
        dictrepr = dict.__repr__(self)
        return '%s(%s)' % (type(self).__name__, dictrepr)
        
    def update(self, *args, **kwargs):
        print('update', args, kwargs)
        for k, v in dict(*args, **kwargs).iteritems():
            self[k] = v

9
আপনি যদি পাইথন 3 ব্যবহার করে থাকেন তবে আপনি এই উদাহরণটি পরিবর্তন করতে চান যাতে printএটি print()ফাংশন এবং update()পদ্ধতিটি items()পরিবর্তে ব্যবহার করে iteritems()
আল সুইগার্ট

আমি আপনার চেষ্টা করেছি, তবে মনে হচ্ছে এটি কেবলমাত্র এক মাত্রার সূচকের
অ্যান্ড্রু

d [key1] কিছু, সম্ভবত একটি অভিধান প্রদান করে। দ্বিতীয় কী সূচক। এই কৌশলটি কাজ করতে পারে না যদি না ফেরত জিনিসটি ঘড়ির আচরণকেও সমর্থন করে।
ম্যাট অ্যান্ডারসন

4
@ অ্যান্ড্রুনাগুইব: কেন এটি নেস্টেড অ্যারেগুলিতে কাজ করা উচিত? নেস্টেড অ্যারে হয় সাধারণ পাইথন ডিক দিয়ে কাজ করে না (যদি আপনি নিজে এটি প্রয়োগ না করেন)
ইগর চুবিন

4
@ অ্যান্ড্রু নাগুইব: __getitem__পরীক্ষা করতে হবে valএবং কেবল শর্তসাপেক্ষে এটি করা দরকার - যেমনif isinstance(val, dict): ...
মার্টিনো

14

সাবক্লাসিং UserDictবা বিবেচনা করুন UserList। এই ক্লাসগুলি সাধারণ অবস্থায় সাবক্ল্যাসড করার উদ্দেশ্যে করা হয়েছে dictএবং listতা নয় এবং এতে অপ্টিমাইজেশন রয়েছে।


9
রেফারেন্সের জন্য, পাইথন ৩.6 নথিতে ডকুমেন্টেশনটিতে বলা হয়েছে "ডিক থেকে সরাসরি সাবক্লাস করার ক্ষমতা দ্বারা এই শ্রেণীর প্রয়োজন আংশিকভাবে পরিপূরক করা হয়েছে; তবে এই শ্রেণীর সাথে কাজ করা আরও সহজ হতে পারে কারণ অন্তর্নিহিত অভিধানটি বৈশিষ্ট্য হিসাবে অ্যাক্সেসযোগ্য"।
শান

@ এবং একটি উদাহরণ সহায়ক হতে পারে।
বসন্ত গণেশ


9

এর ফলে ফলাফলটি পরিবর্তন করা উচিত নয় (ভাল লগিংয়ের প্রান্তিক মানগুলির জন্য যা কাজ করা উচিত): আপনার আরম্ভ করা উচিত:

def __init__(self,*args,**kwargs) : dict.__init__(self,*args,**kwargs) 

পরিবর্তে, কারণ আপনি যদি ডিক্টওয়াচ ([(1,2), (2,3)]) বা ডিকট ওয়াচ (a = 1, খ = 2) দিয়ে আপনার পদ্ধতিটি কল করেন তবে এটি ব্যর্থ হবে।

(বা, আরও ভাল, এর জন্য কোনও কনস্ট্রাক্টর সংজ্ঞায়িত করবেন না)


আমি কেবল dict[key]অ্যাক্সেসের ফর্মটি নিয়েই উদ্বিগ্ন , তাই এটি কোনও সমস্যা নয়।
মাইকেল মায়ার

1

আপনাকে যা করতে হবে তা হ'ল

class BatchCollection(dict):
    def __init__(self, inpt={}):
        super(BatchCollection, self).__init__(inpt)

আমার ব্যক্তিগত ব্যবহারের জন্য একটি নমুনা ব্যবহার

### EXAMPLE
class BatchCollection(dict):
    def __init__(self, inpt={}):
        super(BatchCollection, self).__init__(inpt)

    def __setitem__(self, key, item):
        if (isinstance(key, tuple) and len(key) == 2
                and isinstance(item, collections.Iterable)):
            # self.__dict__[key] = item
            super(BatchCollection, self).__setitem__(key, item)
        else:
            raise Exception(
                "Valid key should be a tuple (database_name, table_name) "
                "and value should be iterable")

দ্রষ্টব্য : কেবল অজগর 3 এ পরীক্ষা করা হয়েছে


0

অ্যান্ড্রু পেট উত্তরটি সম্পূর্ণ করতে, এখানে dictএবং এর মধ্যে পার্থক্য দেখানোর একটি উদাহরণ রয়েছেUserDict :

ডিকটি সঠিকভাবে ওভাররাইট করা মুশকিল:

class MyDict(dict):

  def __setitem__(self, key, value):
    super().__setitem__(key, value * 10)


d = MyDict(a=1, b=2)  # Bad! MyDict.__setitem__ not called
d.update(c=3)  # Bad! MyDict.__setitem__ not called
d['d'] = 4  # Good!
print(d)  # {'a': 1, 'b': 2, 'c': 3, 'd': 40}

UserDictউত্তরাধিকার সূত্রে প্রাপ্ত collections.abc.MutableMapping, তাই কাস্টমাইজ করা অনেক সহজ:

class MyDict(collections.UserDict):

  def __setitem__(self, key, value):
    super().__setitem__(key, value * 10)


d = MyDict(a=1, b=2)  # Good: MyDict.__setitem__ correctly called
d.update(c=3)  # Good: MyDict.__setitem__ correctly called
d['d'] = 4  # Good
print(d)  # {'a': 10, 'b': 20, 'c': 30, 'd': 40}

একইভাবে, আপনাকে কেবল __getitem__স্বয়ংক্রিয়ভাবে সামঞ্জস্য করতে প্রয়োগ করতে হবে key in my_dict,my_dict.get ...

দ্রষ্টব্য: UserDictএটির একটি সাবক্লাস নয় dict, সুতরাং isinstance(UserDict(), dict)ব্যর্থ হবে (তবে isinstance(UserDict(), collections.abc.MutableMapping)কাজ করবে)

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