【问题标题】:How to test if object is a mapping (supports **O usage)如何测试对象是否为映射(支持**O用法)
【发布时间】:2014-03-20 00:01:20
【问题描述】:

我需要测试从带有ConfigParser 的文件(和evaled)读入的对象是否是映射。

不完全确定这里的术语,但让我解释一下。鉴于我的对象被称为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? 中所述

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

所以在加载对象时,我是否必须将上面的测试器功能(没有打印)作为我自己的映射测试

try:
    tester(**O)
except TypeError:
    O = {}

或者 python 是否有一个内置的方法来测试这个,就像对可迭代对象一样?好像应该有。

编辑

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

【问题讨论】:

标签: python mapping


【解决方案1】:

使用collections.abc.MappingABC:

from collections.abc import Mapping

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

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

演示:

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

【讨论】:

  • 但是它必须是从 Mapping 或者是映射的东西派生出来的,这真的和支持 ** 一样吗?
  • @deinonychusaur:不,Mapping 是一个 ABC,一个抽象基类,任何支持 方法 的对象都被视为一个实例。其实不需要继承Mapping,实现功能就够了。
  • 好的,感谢您的快速回复,我似乎只是感到困惑,但 python 映射概念似乎并不存在,所以希望它也能对其他人有所帮助。
【解决方案2】:

有些对象可能不是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

【讨论】:

  • 所以你的意思是,唯一真正的了解方法是测试,或者可能使用dir(尽管这会降低置信度)?
  • 不,我是说当all(hasattr(obj, attr) for attr in ('keys', '__getitem__')) 是True 时,tester(**obj) 有效。
猜你喜欢
  • 2019-09-15
  • 2011-04-30
  • 2012-01-03
  • 1970-01-01
  • 1970-01-01
  • 2010-10-09
  • 1970-01-01
  • 2018-04-20
  • 1970-01-01
相关资源
最近更新 更多