2013-06-27 49 views
0

我正在研究一個需要採用任意Python對象的方法的項目,並且該對象的行爲類似於dictlisttuple--這意味着它支持通過鍵或索引 - 我的方法應該返回一個可以遍歷對象的鍵值或索引值對的迭代器。如果迭代器只是遍歷對象鍵或索引,那對我的目的也是可以的。下面是到目前爲止,我已經得到了代碼:如何獲得遍歷任意Python對象的鍵/索引的迭代器?

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

我是否忽視了一種顯而易見的方式來獲得我所需要的 - 即對任意對象的鍵或索引(或通過其鍵值或索引值對)的迭代器?

回答

1

你想用在collections module定義的基本知識只有檢測映射(因爲要遍歷鍵值對,而不是鍵),並使用標準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()調用;它接受任何可迭代的序列對象並返回一個將對其進行操作的迭代器對象。它支持實現支持一個.__getitem__()方法iterator protocol和對象兩個對象:

[...] O必須是支持迭代協議(該__iter__()方法)的集合的對象,或者它必須支持序列協議(__getitem__()方法,整數參數起始於0)。

那麼,collections.Sequence尋找既__getitem____len__方法,iter()只查找__getitem__

請注意,您不應該接受和處理太多不同類型的東西,例如,這裏不應該有字符串的例外。重新考慮你的代碼,或許你承諾處理的內容會更加嚴格。

+0

@FMc:所以你是;我的觀點是任何可迭代的東西都應該支持'iter()'。 –

+0

@FMc:'iter()'上的'enumerate()'不起作用? –

+0

有*總是*限制什麼可以實現。如果一個對象沒有提供所有被識別爲映射的方法,那麼它就是一個序列,除非它甚至沒有'__getitem__'方法。這是它應該結束的地方。 –