অনুশীলন হিসাবে এবং বেশিরভাগ আমার নিজের বিনোদনের জন্য, আমি ব্যাকট্র্যাকিং প্যাক্র্যাট পার্সার প্রয়োগ করছি। এর অনুপ্রেরণা হ'ল হাইজেনিক ম্যাক্রোস কীভাবে একটি অ্যালগল জাতীয় ভাষায় কাজ করবে (সিনট্যাক্স ফ্রি লিস্প উপভাষায় আপনি সাধারণত সেগুলিকে খুঁজে পান) সম্পর্কে আরও ভাল ধারণা পেতে চাই। এ কারণে, ইনপুটটির মাধ্যমে বিভিন্ন পাসগুলি বিভিন্ন ব্যাকরণ দেখতে পারে, সুতরাং ক্যাশেড পার্সের ফলাফলগুলি অবৈধ unless যদি না আমি ক্যাশেড পার্সের ফলাফলের পাশাপাশি ব্যাকরণের বর্তমান সংস্করণও সঞ্চয় না করি। ( সম্পাদনা : কী-মান সংগ্রহের এই ব্যবহারের একটি পরিণতি হ'ল এগুলি অপরিবর্তনীয় হওয়া উচিত, তবে ইন্টারফেসটি তাদের পরিবর্তিত হতে দেওয়ার জন্য আমি প্রকাশ করার ইচ্ছা করি না, সুতরাং পরিবর্তনীয় বা অপরিবর্তনীয় সংগ্রহগুলি ভাল)
সমস্যাটি হ'ল পাইথন ডিক্টস অন্যান্য ডিক্টের চাবি হিসাবে উপস্থিত হতে পারে না। এমনকি একটি টিপল ব্যবহার করা (যেমনটি আমি যেভাবেই করবো) কোনও সাহায্য করে না।
>>> cache = {}
>>> rule = {"foo":"bar"}
>>> cache[(rule, "baz")] = "quux"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'
>>>
আমার ধারণা এটি পুরোপুরি টিপলস হতে হবে। এখন পাইথন স্ট্যান্ডার্ড লাইব্রেরিতে আমার যা প্রয়োজন তা প্রায় সরবরাহ করে, collections.namedtupleখুব আলাদা সিনট্যাক্স রয়েছে তবে এটি কী হিসাবে ব্যবহার করা যেতে পারে। উপরের অধিবেশন থেকে অব্যাহত:
>>> from collections import namedtuple
>>> Rule = namedtuple("Rule",rule.keys())
>>> cache[(Rule(**rule), "baz")] = "quux"
>>> cache
{(Rule(foo='bar'), 'baz'): 'quux'}
ঠিক আছে. তবে যে নিয়মটি আমি ব্যবহার করতে চাইছি তার প্রতিটি সম্ভাব্য সংমিশ্রণের জন্য আমাকে একটি ক্লাস তৈরি করতে হবে, যা এতটা খারাপ নয়, কারণ প্রতিটি পার্স নিয়ম জানে যে এটি ঠিক কী পরামিতি ব্যবহার করে, তাই ক্লাস একই সময়ে সংজ্ঞায়িত করা যায় নিয়মকে বিশ্লেষণ করে এমন ফাংশন হিসাবে।
সম্পাদনা: এসগুলির সাথে একটি অতিরিক্ত সমস্যা namedtupleহ'ল তারা কঠোরভাবে অবস্থানগত। দুটি টিপল যা দেখতে দেখতে আলাদা হতে হবে তা আসলে একই হতে পারে:
>>> you = namedtuple("foo",["bar","baz"])
>>> me = namedtuple("foo",["bar","quux"])
>>> you(bar=1,baz=2) == me(bar=1,quux=2)
True
>>> bob = namedtuple("foo",["baz","bar"])
>>> you(bar=1,baz=2) == bob(bar=1,baz=2)
False
tl'dr: আমি কীভাবে এস পাব যা অন্যগুলির dictকী হিসাবে ব্যবহার করা যেতে পারে dict?
উত্তরে কিছুটা হ্যাক করা, আমি ব্যবহার করছি আরও সম্পূর্ণ সমাধান এখানে। মনে রাখবেন যে ফলস্বরূপ ডিক্সকে ব্যবহারিক উদ্দেশ্যে অস্পষ্টভাবে পরিবর্তনযোগ্য করার জন্য এটি কিছুটা অতিরিক্ত কাজ করে। অবশ্যই এটি কল করে এখনও এটি চারপাশে হ্যাক করা বেশ সহজ dict.__setitem__(instance, key, value)তবে আমরা সকলেই এখানে প্রাপ্তবয়স্ক।
class hashdict(dict):
"""
hashable dict implementation, suitable for use as a key into
other dicts.
>>> h1 = hashdict({"apples": 1, "bananas":2})
>>> h2 = hashdict({"bananas": 3, "mangoes": 5})
>>> h1+h2
hashdict(apples=1, bananas=3, mangoes=5)
>>> d1 = {}
>>> d1[h1] = "salad"
>>> d1[h1]
'salad'
>>> d1[h2]
Traceback (most recent call last):
...
KeyError: hashdict(bananas=3, mangoes=5)
based on answers from
http://stackoverflow.com/questions/1151658/python-hashable-dicts
"""
def __key(self):
return tuple(sorted(self.items()))
def __repr__(self):
return "{0}({1})".format(self.__class__.__name__,
", ".join("{0}={1}".format(
str(i[0]),repr(i[1])) for i in self.__key()))
def __hash__(self):
return hash(self.__key())
def __setitem__(self, key, value):
raise TypeError("{0} does not support item assignment"
.format(self.__class__.__name__))
def __delitem__(self, key):
raise TypeError("{0} does not support item assignment"
.format(self.__class__.__name__))
def clear(self):
raise TypeError("{0} does not support item assignment"
.format(self.__class__.__name__))
def pop(self, *args, **kwargs):
raise TypeError("{0} does not support item assignment"
.format(self.__class__.__name__))
def popitem(self, *args, **kwargs):
raise TypeError("{0} does not support item assignment"
.format(self.__class__.__name__))
def setdefault(self, *args, **kwargs):
raise TypeError("{0} does not support item assignment"
.format(self.__class__.__name__))
def update(self, *args, **kwargs):
raise TypeError("{0} does not support item assignment"
.format(self.__class__.__name__))
# update is not ok because it mutates the object
# __add__ is ok because it creates a new object
# while the new object is under construction, it's ok to mutate it
def __add__(self, right):
result = hashdict(self)
dict.update(result, right)
return result
if __name__ == "__main__":
import doctest
doctest.testmod()
hashdict, অপরিবর্তনীয় হতে হবে কমপক্ষে করার পরে এটিকে হ্যাশ শুরু, তবে কেন ক্যাশে নাkeyএবংhashগুণাবলীর যেমন মানhashdictবস্তু? আমি পরিবর্তন করেছি__key()এবং__hash__(), এবং এটি আরও দ্রুতগতিতে নিশ্চিত করে পরীক্ষা করেছি। এসও মন্তব্যগুলিতে ফর্ম্যাট কোডটি মঞ্জুরি দেয় না, তাই আমি এটি এখানে লিঙ্ক করব: sam.aiki.info/hashdict.py