2013-05-10 2 views
-1
class FrozenDict(dict): 
    def __init__(self,default=None): 
     if default: self.update(default) 
    def __hash__(self): 
     return id(self) 


dictionary={FrozenDict({"dsa":"saas"}):"Hi"} 

eval(str(dictionary)) 


TypeError: unhashable type: 'dict' 

Я пытаюсь преобразовать строку в ее «сырую» форму, поэтому я не получаю сообщение об ошибке. 'Сырая' форма словаря будет {FrozenDict({"dsa":"saas"}):"Hi"}Преобразование строки Python в исходную форму

Что-то вроде этого:

eval(rawform(dictionary)) 

был бы удивительным ..

Edit:

OrderedDict, кажется, работает, кто-нибудь знает почему?

Edit:

Это то, что я пытаюсь загрузить с помощью pickle.loads

S'{\'Source\': {\'CollideObjects\': [], \'Depth\': 0, \'Events\': OrderedDict([(({\'function\': \'bi_create\', \'class\': \'\', \'name\': \'Create\'}, 0), {{\'data\': {\'raw\': \'Set saddasdsadsa to: (,)\', \'data\': {u\'function\': u\'asddsaadsasddsasdasdasddsasdasda(x=None,y=None)\', u\'src\': u\'GUI\\\\movetoxy.xml\', \'code\': u\'\\nreal=[0,0]\\ncurrent=self.sdsdadsaadssd()\\nif x!=None:\\n\\treal[0]=float(x)\\nelse:\\n\\treal[0]=current[1]\\nif y!=None:\\n\\treal[1]=float(y)\\nelse:\\n\\treal[1]=current[1]\\nself.SetPos(*real)\\n\', \'return\': u"\'Set Position to: (\'+str(x)+\',\'+str(y)+\')\'", u\'title\': u\'Set Position\', u\'image\': u\'modules\\\\Core\\\\images\\\\pos.png\', \'dddddddddd\': u\'self.SetPosition(,)\', \'html\': u\'C:\\\\sadsdadsad\\\\dsasasddsa\\\\modules\\\\Core\\\\GUI\\\\movetoxy.xml\', \'apply\': {\'name\': \'Self\', \'value\': \'\'}, u\'holder\': u\'False\', u\'class\': u\'object\'}, \'dialog\': u\'Set Position\', \'name_var\': {u\'y\': {\'class\': u\'wxTextCtrl\', \'value\': u\'\'}, u\'x\': {\'class\': u\'wxTextCtrl\', \'value\': u\'\'}}}}: {}})]), \'Sprite\': \'\'}, \'Window\': \'\', \'Type\': \'Object\', \'Name\': u\'Object1\', \'Id\': 1}' 
+0

Не возвращайте 'id (self)' для '__hash__'; что делает ваши ключи невозможными для поиска снова. –

+0

Хм, я получил это из Интернета. У вас есть какие-то предложения о том, что я должен изменить вместо этого? –

+0

См. Http://docs.python.org/2/reference/datamodel.html#object.__hash__ о том, что должен делать метод '__hash__'. –

ответ

1

Чтобы создать "rawform", вам необходимо переопределить __repr__:

class FrozenDict(dict): 
    def __init__(self,default=None): 
     if default: self.update(default) 
    def __hash__(self): 
     return id(self) 
    def __repr__(self): 
     return "FrozenDict(%s)" % dict.__repr__(self) 


print FrozenDict({"dsa":"saas"}) 

dictionary={FrozenDict({"dsa":"saas"}):"Hi"} 

print eval(str(dictionary)) 

В результате я получаю:

FrozenDict({'dsa': 'saas'}) 
{FrozenDict({'dsa': 'saas'}): 'Hi'} 
3

Для этого нет никаких оснований вы не могли pickle его вместо этого?

import cPickle as pickle 
# This can't be `eval`d, but... 
string = pickle.dumps(dictionary) 
# ... you can use it to get back the original object 
obj = pickle.loads(string) 

Конечно, это не делает использование eval, но если использование eval можно избежать, оно должно быть.

+0

Хмм круто. ill try this out –

+0

Im фактически сохраняет словарь в таблице sqlite3, и когда я загружаю словарь из таблицы, я получаю: 'TypeError: должен быть строкой, а не unicode', знаете ли вы, как лучше всего это исправить? –

+0

Возможно, вы могли бы включить пример данных, для которых у вас возникла проблема, и тогда мы сможем более легко диагностировать :-) –

1

Есть несколько проблем с тем, что вы делаете.

Во-первых, причина того, что ваш eval не работает, потому что вы не переопределить метод __repr__ в вашем FrozenDict классе, так eval производит регулярный словарь, а не новый FrozenDict и получаю сообщение об ошибке при попытке использовать это как словарь. Это относительно легко исправить:

def __repr__(self): 
    return "FrozenDict({})".format(super(FrozenDict, self).__repr__()) 

Это позволит вам использовать str или repr вашего объекта как код Python, чтобы воссоздать его.

Однако есть и другие проблемы, которые это не исправить. Например, в настоящее время вы можете иметь словари хэш-разному, даже если они считаются равными:

a = FrozenDict({"foo":"bar"}) 
b = FrozenDict({"foo":"bar"}) 

a == b    # True! 
hash(a) == hash(b) # False! 

Это делает невозможным, чтобы соответствовать вашему замороженный словаря в хэш-таблице, если вы не имеете точно такой же объект, который вы использовали когда вы вставили его.

Лучшим подходом, вероятно, будет вычисление хэша на основе ключей и значений, которые были в словаре. Что-то, как это будет лучше:

def __hash__(self): 
    return hash(tuple(sorted(self.items())) 

Однако, теперь вы будете работать в другой вопрос: Ваш словарь изменчиво, и его хэш может измениться при добавлении или удалении значений из него.Это очень плохо:

a = FrozenDict() 
d = {a: "a"} 

a["foo"] = "bar" 

d[a]   # raises a KeyError! 
d[FrozenDict()] # perhaps surprisingly, so does this! 

Чтобы исправить это, вы, вероятно, нужно переопределить __setitem__, __delitem__ и update поднять исключения, когда они называются. Я полагаю, что если вы знаете, что не будете изменять значения после добавления их в словарь, вы можете пропустить это, но если вы хотите, чтобы ваш класс был в целом полезен, это необходимо. Могут быть и другие методы мутаций, которые я тоже забыл.

Смежные вопросы