0

我正在做一个项目,我需要一个采用任意 Python 对象的方法,如果该对象的行为类似于dictlisttuple- 意味着它支持通过键或索引访问集合成员的想法 -我的方法应该返回一个可以遍历对象的键值或索引值对的迭代器。如果迭代器简单地遍历对象键或索引,这对我的目的也很好。这是我到目前为止的代码:

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__()-- 或类似的东西。

我是否忽略了一种明显的方式来获得我需要的东西——即,对任意对象的键或索引(或其键值或索引值对)的迭代器?

4

1 回答 1

1

您只想使用collections模块中定义的 ABC来检测映射(因为您想迭代键值对而不是键),并对其他所有内容使用标准iter()函数

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()通话;它接受任何可迭代的序列对象并返回将对其进行操作的迭代器对象。它支持实现迭代器协议的对象和支持.__getitem__()方法的对象:

[...] o必须是支持迭代协议(__iter__()方法)的集合对象,或者它必须支持序列协议(__getitem__()整数参数从 开始的方法0)。

所以 wherecollections.Sequence同时查找 a__getitem__和 a__len__方法,iter()只查找__getitem__.

请注意,您不应该过度接受和处理太多不同的类型;例如,这里的字符串不应该有例外。重新考虑您的代码,以便对您承诺处理的内容更加严格。

于 2013-06-27T15:48:43.337 回答