如何测试对象是否为映射(支持** O用法)

时间:2014-02-19 14:57:53

标签: python mapping

我需要测试从eval编辑的文件(和ConfigParser ed)读入的对象是否为映射。

这里的术语不完全确定,但让我解释一下。鉴于我的对象被称为O,它必须支持以下列方式使用:

def tester(**kwargs):
     print kwargs

tester(**O)

如果O不支持**,则会导致TypeError,例如TypeError: test() argument after ** must be a mapping, not tuple

这是一个非常简单的场景,但我需要知道O在使用它之前会起作用,我需要绝对肯定它不会失败。如果我测试O是可迭代的,我会使用类似的东西:

try:
   iter(O)
except:
   O = tuple()

In Python, how do I determine if an object is iterable?

中所述

我找不到映射的任何并行。正如上面相同的答案中所讨论的,使用isinstancecollections并不是一个好的解决方案。

所以在加载像

这样的对象时,我必须将我的测试器功能(没有打印)作为我自己的映射测试
try:
    tester(**O)
except TypeError:
    O = {}

或者python是否有内置的测试方法,就像迭代一样?似乎应该有一个。

修改

实际上上面的链接答案从未对isinstance方法发表过反应,应该更好地阅读...

2 个答案:

答案 0 :(得分:8)

使用collections.Mapping ABC:

from collections import Mapping

if isinstance(O, Mapping):
    # O is a mapping

这支持将实现正确的方法的任何对象视为映射,包括dict

演示:

>>> from collections import Mapping
>>> isinstance({}, Mapping)
True
>>> isinstance((), Mapping)
False

答案 1 :(得分:3)

某些对象可能不是collections.Mapping的实例,但可以使用双星语法(**)解压缩:

import collections
def tester(**kwargs):
     print kwargs

class D:
    "http://stackoverflow.com/a/8601389/190597 (Raymond Hettinger)"
    def keys(self):
        return ['a', 'b']
    def __getitem__(self, key):
        return key.upper()

obj = D()
tester(**obj)
# {'a': 'A', 'b': 'B'}

print(isinstance(obj, collections.Mapping))
# False

obj必须提供的最小界面是keys__getitem__

print(all(hasattr(obj, attr) for attr in ('keys', '__getitem__')))
# True