Bir alıştırma olarak ve çoğunlukla kendi eğlencem için, geriye dönük bir paket ayrıştırıcı uyguluyorum. Bunun ilham kaynağı, hijyenik makroların algol benzeri bir dilde (normalde bulduğunuz sözdizimsiz lisp lehçelerine uygulandığı gibi) nasıl çalışacağı hakkında daha iyi bir fikre sahip olmak istiyorum. Bu nedenle, girişteki farklı geçişler farklı gramerler görebilir, bu nedenle önbelleğe alınmış ayrıştırma sonuçları, dilbilgisinin geçerli sürümünü önbelleğe alınmış ayrıştırma sonuçlarıyla birlikte saklamadığım sürece geçersizdir. ( DÜZENLEME : Anahtar-değer koleksiyonlarının bu kullanımının bir sonucu, bunların değişmez olmaları gerektiğidir, ancak değiştirilmelerine izin vermek için arabirimi ortaya çıkarmayı düşünmüyorum, bu nedenle değiştirilebilir veya değişmez koleksiyonlar iyidir)
Sorun şu ki, python dicts diğer diktlere anahtar olarak görünemez. Bir demet kullanmak bile (zaten yapacağım gibi) yardımcı olmuyor.
>>> cache = {}
>>> rule = {"foo":"bar"}
>>> cache[(rule, "baz")] = "quux"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'
>>>
Sanırım baştan sona tuple olmalı. Şimdi piton standart kütüphane ihtiyacım yapardım yaklaşık sağlar, collections.namedtupleçok farklı bir sözdizimi vardır, ama olabilir bir anahtar olarak kullanılabilir. yukarıdaki oturumdan devam ediyor:
>>> from collections import namedtuple
>>> Rule = namedtuple("Rule",rule.keys())
>>> cache[(Rule(**rule), "baz")] = "quux"
>>> cache
{(Rule(foo='bar'), 'baz'): 'quux'}
Tamam. Ancak, kullanmak istediğim kuraldaki her olası anahtar kombinasyonu için bir sınıf oluşturmam gerekiyor, bu o kadar da kötü değil çünkü her ayrıştırma kuralı tam olarak hangi parametreleri kullandığını biliyor, böylece sınıf aynı anda tanımlanabilir. kuralı ayrıştıran işlev olarak.
Düzenleme: namedtuples ile ilgili ek bir sorun , kesinlikle konumsal olmalarıdır. Farklı olmaları gerektiği gibi görünen iki grup aslında aynı olabilir:
>>> 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: Diğer e-postaların dictanahtarı olarak kullanılabilecek e- postaları nasıl edinebilirim dict?
Cevapları biraz hackledikten sonra, işte kullandığım daha eksiksiz çözüm. Bunun, sonuçta ortaya çıkan kararları pratik amaçlar için belirsiz bir şekilde değişmez hale getirmek için biraz fazladan çalışma yaptığını unutmayın. Elbette arayarak etrafından dolaşmak oldukça kolay dict.__setitem__(instance, key, value)ama burada hepimiz yetişkiniz.
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()
hashdictazından hashing oluşturmaya başladıktan sonra değişmez olmalıdır, öyleyse nedenkeyvehashdeğerlerinihashdictnesnenin öznitelikleri olarak önbelleğe almayasınız? Çok daha hızlı olduğunu doğrulamak için değiştirdim__key()ve__hash__()test ettim. SO yorumlarda biçimlendirilmiş koda izin vermez, bu yüzden buraya bağlayacağım