如何区分序列和映射
我想对一个参数进行操作,这个参数可能是类似于地图的对象,也可能是类似于序列的对象。我知道没有一种方法可以百分之百可靠地检查类型,但我希望能找到一个比较稳妥的解决方案。
根据这个 回答,我知道如何判断某个东西是否是一个序列,我可以在检查对象是否是一个地图之后再进行这个检查。
def ismap(arg):
# How to implement this?
def isseq(arg):
return hasattr(arg,"__iter__")
def operation(arg):
if ismap(arg):
# Do something with a dict-like object
elif isseq(arg):
# Do something with a sequence-like object
else:
# Do something else
因为序列可以看作是一个地图,其中键是整数,我是不是应该尝试找一个不是整数的键?或者我可以看看它的字符串表示?还是说...?
更新
我选择了SilentGhost的回答,因为看起来是最“正确”的,但根据我的需求,这里是我最终实现的解决方案:
if hasattr(arg, 'keys') and hasattr(arg, '__getitem__'):
# Do something with a map
elif hasattr(arg, '__iter__'):
# Do something with a sequence/iterable
else:
# Do something else
其实,我不想依赖于一个抽象基类(ABC),因为有很多自定义类的行为像序列和字典,但它们并没有扩展Python的集合ABC(见@Manoj的评论)。我觉得键属性(有人提到过但后来删除了回答)是检查映射的一个不错的方法。
扩展了序列和映射ABC的类也可以用这个解决方案。
2 个回答
4
序列(比如列表和元组)有一个叫做 __add__
的方法,这个方法用来实现 + 这个运算符。而映射(比如字典)没有这个方法,因为往映射里添加东西需要同时提供一个键和一个值,而 + 运算符只需要一个右边的值。
所以你可以尝试:
def ismap(arg):
return isseq(arg) and not hasattr(arg, "__add__")
9
>>> from collections import Mapping, Sequence
>>> isinstance('ac', Sequence)
True
>>> isinstance('ac', Mapping)
False
>>> isinstance({3:42}, Mapping)
True
>>> isinstance({3:42}, Sequence)
False