2010-08-11 3 views
34

Я заинтересован в том, чтобы взять произвольный диктофон и скопировать его в новый дик, мутируя его по пути.Задание «hashable» о значении Python

Одна мутация, которую я хотел бы сделать, это замена ключей и значений. К сожалению, некоторые ценности сами по себе являются диктофонами. Тем не менее, это генерирует ошибку «unhashable type: 'dict». На самом деле, я не против просто подчеркивать значение и давать ему ключ. Но, я хотел бы быть в состоянии сделать что-то вроде этого:

for key in olddict: 
    if hashable(olddict[key]): 
    newdict[olddict[key]] = key 
    else 
    newdict[str(olddict[key])] = key 

Есть чистый способ сделать это, что не вовлекают улавливать исключение и разбор строки сообщения для «unhashable типа» ?

ответ

38

Поскольку Python 2.6 вы можете использовать абстрактный базовый класс collections.Hashable:

import collections 
>>> isinstance({}, collections.Hashable) 
False 
>> isinstance(0, collections.Hashable) 
True 

Этот подход также кратко упомянуто в документации __hash__.

Doing so means that not only will instances of the class raise an appropriate TypeError when a program attempts to retrieve their hash value, but they will also be correctly identified as unhashable when checking isinstance(obj, collections.Hashable) (unlike classes which define their own __hash__() to explicitly raise TypeError).

+6

Это работает, если кортеж содержит список/словарь? –

+4

Нет, и это то, что вы можете определить только во время выполнения, так как до этого содержимое списка вообще неизвестно. 'hash (([],))' дает 'TypeError: unhashable type: 'list'' – Syncopated

+1

Небольшое предупреждение для людей, использующих Python 2.7' isinstance (bytearray ([0xa]), collections.Hashable)) 'возвращает' True', но 'hash (bytearray ([0xa]))' fail с 'TypeError: unhashable type: 'bytearray''. – RedX

13
def hashable(v): 
    """Determine whether `v` can be hashed.""" 
    try: 
     hash(v) 
    except TypeError: 
     return False 
    return True 
+3

Ned - это именно то, что я бы предпочел избежать. Кроме того, эта функция будет ломать TypeErrors, которые не являются «не подлежащими типу». –

+5

Есть только один TypeError, который hash() будет поднимать. Или поочередно, независимо от того, что делает хеш TypeError, он будет держать вашу ценность от хэширования. Я даже утверждаю, что это должно перехватывать Exception, потому что на самом деле не имеет значения, почему hash() не удалось: сбой в hash() делает ваше значение нечувствительным. Можете ли вы сказать больше о том, почему вы хотите избежать таких исключений? Это инкапсулирует обработку исключений в хорошую функцию и делает ваш примерный код выше, работает отлично. –

+1

Возможно, это скорее философский момент - вопрос заключается не в «исключительном условии» того, что он не сотрясается из-за какого-то «состояния уродства», а в вопросе о функциональности, доступной для типа. Если это имеет смысл. –

1

Все хешируемые встроенные объекты python имеют метод .__hash__(). Вы можете это проверить.

olddict = {"a":1, "b":{"test":"dict"}, "c":"string", "d":["list"] } 

for key in olddict: 
    if(olddict[key].__hash__): 
     print str(olddict[key]) + " is hashable" 
    else: 
     print str(olddict[key]) + " is NOT hashable" 

выход

1 is hashable 
string is hashable 
{'test': 'dict'} is NOT hashable 
['list'] is NOT hashable 
+1

Предупреждение об этом: В Python 2.5 это даст: '{ 'test': 'dict'} hashable'.Это также может привести к неправильному результату в более новых версиях, если класс определяет '__hash__', чтобы поднять TypeError. –

0

Почему бы не использовать утка печатать?

for key in olddict: 
    try: 
     newdict[olddict[key]] = key 
    except TypeError: 
     newdict[str(olddict[key])] = key 
Смежные вопросы