एक अभ्यास के रूप में, और ज्यादातर अपने स्वयं के मनोरंजन के लिए, मैं एक बैकट्रैकिंग पैकरैट पार्सर को लागू कर रहा हूं। इसके लिए प्रेरणा यह है कि मैं एक बेहतर विचार रखना चाहूंगा कि कैसे एक उच्च-स्तरीय भाषा में हाइजीनिक मैक्रोज़ काम करेंगे (जैसा कि वाक्यविन्यास मुक्त लिस्प बोलियों के लिए आपको आमतौर पर इसमें मिलता है)। इस वजह से, इनपुट के माध्यम से अलग-अलग पास अलग-अलग व्याकरण देख सकते हैं, इसलिए कैश्ड पार्स परिणाम अमान्य हैं, जब तक कि मैं कैश्ड पार्स परिणामों के साथ व्याकरण के वर्तमान संस्करण को भी संग्रहीत नहीं करता। ( संपादित करें) : कुंजी-मूल्य संग्रह के इस उपयोग का एक परिणाम यह है कि उन्हें अपरिवर्तनीय होना चाहिए, लेकिन मैं उन्हें बदलने की अनुमति देने के लिए इंटरफ़ेस को उजागर करने का इरादा नहीं करता हूं, इसलिए या तो परिवर्तनशील या अपरिवर्तनीय संग्रह ठीक हैं)
समस्या यह है कि अजगर dicts अन्य dicts की कुंजी के रूप में प्रकट नहीं हो सकते हैं। यहां तक कि एक टपल का उपयोग करना (जैसा कि मैं वैसे भी कर रहा हूं) मदद नहीं करता है।
>>> cache = {}
>>> rule = {"foo":"bar"}
>>> cache[(rule, "baz")] = "quux"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'
>>>
मुझे लगता है कि यह नीचे सभी तरह से tuples होना चाहिए। अब अजगर मानक पुस्तकालय लगभग वही प्रदान करता है 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
s प्राप्त कर सकता हूं जिसे अन्य dict
s की कुंजी के रूप में उपयोग किया जा सकता है ?
जवाबों पर थोड़ा सा हैक होने के बाद, यहाँ और अधिक पूर्ण समाधान का उपयोग कर रहा हूँ। ध्यान दें कि यह व्यावहारिक उद्देश्यों के लिए परिणामी dicts को अपरिवर्तनीय बनाने के लिए थोड़ा अतिरिक्त काम करता है। बेशक, यह अभी भी कॉल करके इसके चारों ओर हैक करना काफी आसान है, 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
, अपरिवर्तनीय होना चाहिए कम से कम करने के बाद उसे hashing शुरू करते हैं, तो क्यों कैश नहींkey
औरhash
की विशेषताओं के रूप में मानhashdict
वस्तु? मैंने संशोधित किया__key()
और__hash__()
, और यह पुष्टि करने के लिए परीक्षण किया कि यह बहुत तेज़ है। SO टिप्पणियों में फ़ॉर्मेट किए गए कोड की अनुमति नहीं देता है, इसलिए मैं इसे यहां लिंक करूंगा