我正在开发一个项目,我需要一个接受任意Python对象的方法,如果该对象的作用类似于dict
,list
或tuple
- 含义它支持通过键或索引访问集合成员的想法 - 我的方法应该返回一个可以遍历对象的键值或索引值对的迭代器。如果迭代器只是遍历对象键或索引,那么对我的目的来说也没问题。这是我到目前为止的代码:
from collections import Mapping, Sequence
# Tuple used to identify string-like objects in Python 2 or 3.
STRINGS = (str, unicode) if str is bytes else (str, bytes)
def get_keyval_iter(obj):
if isinstance(obj, STRINGS): return None
elif isinstance(obj, Sequence): return enumerate(obj)
elif isinstance(obj, Mapping): return getattr(obj, 'iteritems', obj.items)()
else: return None
# For example:
print list(get_keyval_iter([0, 11, 22])) # [(0, 0), (1, 11), (2, 22)]
print list(get_keyval_iter(dict(a = 1, b = 2))) # [('a', 1), ('b', 2)]
print [ get_keyval_iter("foobar") ] # [None]
print [ get_keyval_iter(1234) ] # [None]
我不喜欢这个解决方案有两个原因:(1)在一般原则上,我宁愿查询对象的接口而不是检查它的类型; (2)我的代码将返回None
用于用户定义的类,这些类的对象未通过isinstance
测试,但仍然支持__getitem__
协议,理论上可以给我一个迭代器相关的键或索引。
以下是我想写的代码:return obj.__getitemiter__()
- 或类似内容。
我是否忽略了一种明显的方式来获得我需要的东西 - 即,对任意对象的键或索引(或其键值或索引值对)的迭代器?
答案 0 :(得分:1)
您希望仅使用collections
module中定义的ABC来检测映射(因为您希望迭代键值对而不是键),并将标准iter()
function用于其他所有内容:
import collections
def get_keyval_iter(obj):
if isinstance(obj, collections.Mapping):
return obj.iteritems()
try:
return enumerate(iter(obj))
except TypeError:
# not iterable
return None
注意iter()
电话;它接受任何可迭代的序列对象并返回将对其进行操作的迭代器对象。它支持实现iterator protocol的对象和支持.__getitem__()
方法的对象:
[...] o 必须是支持迭代协议(
__iter__()
方法)的集合对象,或者它必须支持序列协议(__getitem__()
整数参数从0
开始的方法。
因此,collections.Sequence
查找__getitem__
和__len__
方法,iter()
仅查找__getitem__
。
请注意,接受和处理太多不同类型不应过分;例如,这里的字符串不应该有例外。重新思考你的代码可能会更严格地遵守你的承诺。