询问有关Python值的"可持续"

Pau*_*han 42 python

我有兴趣采取一个任意的字典并将其复制到一个新的字典中,一路上改变它.

我想做的一个突变是交换键和值.不幸的是,有些价值观本身就是决定性的.但是,这会生成"不可用类型:'dict'"错误.我真的不介意只是将值字符串化并给它键.但是,我希望能够做到这样的事情:

for key in olddict:
  if hashable(olddict[key]):
    newdict[olddict[key]] = key
  else
    newdict[str(olddict[key])] = key
Run Code Online (Sandbox Code Playgroud)

是否有一种干净的方法来执行此操作,涉及捕获异常并解析"不可用类型"的消息字符串?

Mar*_*ers 52

从Python 2.6开始,您可以使用抽象基类collections.Hashable:

>>> import collections
>>> isinstance({}, collections.Hashable)
False
>>> isinstance(0, collections.Hashable)
True
Run Code Online (Sandbox Code Playgroud)

在文档中也简要提到了这种方法__hash__.

这样做意味着TypeError当程序试图检索其哈希值时,不仅类的实例会引发适当的,而且在检查时它们也将被正确识别为不可用isinstance(obj, collections.Hashable)(与定义它们自己的类__hash__()以明确引发的不同TypeError).

  • 如果元组包含列表/字典,这是否有效? (8认同)
  • 在 Python 3.7.5 中,直接从“collections”导入会引发“DeprecationWarning”。相反,“from collections.abc import Hashable”。 (5认同)
  • **这太糟糕了。** `isinstance(obj, collections.abc.Hashable)` 会为用户定义的类返回误报,这些类会从重写的 `__hash__()` dunder 方法中引发异常。`collections.abc.Hashable` *不能*被信任用于现实世界的可哈希检测。相反,唯一明智的解决方案是尝试“hash(obj)”并报告“False”(如果这样做会引发*任何*异常)。 (5认同)
  • 不,这是您只能在运行时确定的事情,因为在此之前列表的内容通常是未知的.`hash(([],))`给出`TypeError:unhashable type:'list'` (4认同)
  • 在Python 3中是`isinstance(obj,collections.abc.Hashable)`。 (2认同)

Ned*_*der 17

def hashable(v):
    """Determine whether `v` can be hashed."""
    try:
        hash(v)
    except TypeError:
        return False
    return True
Run Code Online (Sandbox Code Playgroud)

  • hash()只会引发一个TypeError.或者,无论TypeError哈希引发什么,它都会使您的值不被哈希处理.我甚至认为这应该捕获Exception,因为hash()失败的原因并不重要:hash()失败会使你的值不可用.你能说更多关于你为什么要避免像这样的例外情况吗?这将异常处理封装在一个很好的函数中,并使您的示例代码完美地工作. (9认同)
  • **这太糟糕了。** `hash()` 内置隐式调用用户定义的 `v.__hash__()` dunder 方法,可以想象,这可能会引发*任何*可能的异常 - 而不仅仅是 `TypeError` 异常。为了概括这一点,请将上面过于具体的子类“TypeError”替换为捕获所有异常的超类“Exception”。 (4认同)
  • 内德 - 这正是我宁愿避免的.此外,此函数将捕获不是"不可用类型"的TypeErrors. (3认同)
  • 我认为你认为这是一个哲学观点是正确的,也许可以归结为静态与动态的世界观.经典的Python思维方式经常尝试事物并捕获异常,而不是试图在理论上有可能提前确定. (3认同)
  • 也许这更多的是一个哲学点 - 问题不是关于由于某种“异常条件”而无法散列的“异常条件”,而是关于类型上可用功能的查询。如果那有意义的话。 (2认同)
  • @Paul Nathan:这是**标准**方法.只需尝试操作; 如果它失败了,那么该物体就不可清洗; 做点别的.如果它工作,那么该对象是可以清洗的,你做了你想做的事情. (2认同)
  • 这种方法不是好习惯!由于堆栈遍历等原因,不鼓励使用异常来检查此类内容 (2认同)

Cha*_*ler 5

所有内置在 python 对象中的 hashable 都有一个.__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"
Run Code Online (Sandbox Code Playgroud)

输出

1 is hashable
string is hashable
{'test': 'dict'} is NOT hashable
['list'] is NOT hashable
Run Code Online (Sandbox Code Playgroud)

  • **这也太糟糕了**。仅仅因为类型定义了“__hash__()”方法,并不意味着该类型的所有可能实例都是可哈希的。例如,考虑“def __hash__(self): raise ValueError('uhoh')”。相反,唯一明智的解决方案是尝试“hash(olddict[key])”并报告“False”(如果这样做引发任何异常)。 (4认同)
  • 关于此的警告:在 Python 2.5 中,这将给出:`{'test': 'dict'}is hashable`。如果类定义 __hash__ 来引发 TypeError,它也可能在新版本中给出错误的结果。 (3认同)