2012-09-07 136 views
12

剛剛寫了一些討厭的代碼,它在Python中迭代了dictlist。我有一種感覺,這不是最好的辦法。迭代Python中的字典或列表

的問題是,爲了遍歷一個字典,這是慣例:

for key in dict_object: 
    dict_object[key] = 1 

但是,關鍵的修改對象的屬性,如果同樣的事情的清單上完成不起作用:

# Throws an error because the value of key is the property value, not 
#  the list index: 

for key in list_object: 
    list_object[key] = 1 

我解決這個問題的方法是寫這個討厭的代碼:

if isinstance(obj, dict): 
    for key in obj: 
     do_loop_contents(obj, key) 
elif isinstance(obj, list): 
    for i in xrange(0, len(obj)): 
     do_loop_contents(obj, i) 

def do_loop_contents(obj, key): 
    obj[key] = 1 

是療法一個更好的方法來做到這一點?

謝謝!

回答

12

我從來沒有必要這樣做,永遠。但是,如果我這樣做,我可能會做這樣的事情:

seq_iter = x if isinstance(x, dict) else xrange(len(x)) 

例如,函數形式:

>>> def seq_iter(obj): 
...  return obj if isinstance(obj, dict) else xrange(len(obj)) 
... 
>>> x = [1,2,3] 
>>> for i in seq_iter(x): 
...  x[i] = 99 
... 
>>> x 
[99, 99, 99] 
>>> 
>>> x = {1: 2, 2:3, 3:4} 
>>> for i in seq_iter(x): 
...  x[i] = 99 
... 
>>> x 
{1: 99, 2: 99, 3: 99} 
+0

只要發現你有一個答案非常類似地雷。唯一的區別是你使用'xrange()'(可以),但結果是相同或非常相似的。+1 – Tadeck

+1

如果isinstance(obj,dict)else xrange(len(obj))'不應該返回obj? –

+0

@tobias_k:很好! Python的範圍符合內聯編輯。 :^) – DSM

2

要符合Python和ducktype-Y,並遵循「問寬恕不許可」,你可以這樣做:

try: 
    iterator = obj.iteritems() 
except AttributeError: 
    iterator = enumerate(obj) 
for reference, value in iterator: 
    do_loop_contents(obj, reference) 

但如果你需要的是鍵/索引:

try: 
    references = obj.keys() 
except AttributeError: 
    references = range(len(obj)) 
for reference in references: 
    do_loop_contents(obj, reference) 

或者作爲一個函數:

def reference_and_value_iterator(iterable): 
    try: 
     return iterable.iteritems() 
    except AttributeError: 
     return enumerate(iterable) 

for reference, value in reference_and_value_iterator(obj): 
    do_loop_contents(obj, reference) 

或者只是引用:

def references(iterable): 
    try: 
     return iterable.keys() 
    except AttributeError: 
     return range(len(iterable)) 

for reference in references(obj): 
    do_loop_contents(obj, reference) 
5

這是正確的做法,但如果由於某種原因,你需要將這兩個對象以相同的方式,您可以創建一個迭代將返回索引/鍵不管是什麼:

def common_iterable(obj): 
    if isinstance(obj, dict): 
     return obj 
    else: 
     return (index for index, value in enumerate(obj)) 

將在你想要的方式運行:

>>> d = {'a': 10, 'b': 20} 
>>> l = [1,2,3,4] 
>>> for index in common_iterable(d): 
    d[index] = 0 

>>> d 
{'a': 0, 'b': 0} 
>>> for index in common_iterable(l): 
    l[index] = 0 

>>> l 
[0, 0, 0, 0] 

或者可能更有效地使用發電機:

def common_iterable(obj): 
    if isinstance(obj, dict): 
     for key in obj: 
      yield key 
    else: 
     for index, value in enumerate(obj): 
      yield index 
+0

這實際上並不是一個'iterator',它只是將'list'或'dict'轉換爲一個一致格式的迭代。你可以定義一個迭代器工廠,它使用迭代器協議使用'next'和'__iter__'來完成。 –

+0

@ sr2222:好的,它是可迭代的。我也可以讓它成爲一個發電機,可能會提升性能。 – Tadeck

+0

你的第二版'common_iterable'是不必要的。從第一個版本開始,'(index for index,value in enumerate(obj))'已經是一個生成器,'for key in obj:yield key'只是增加了第一版'common_iterable' –

1
test_list = [2, 3, 4] 
for i, entry in enumerate(test_list): 
    test_list[i] = entry * 2 
print(test_list) # Gives: [4, 6, 8] 

但你可能需要一個列表理解:

test_list = [2, 3, 4] 
test_list = [entry * 2 for entry in test_list] 
print(test_list) # Gives: [4, 6, 8] 
1

你可能只是想有一個不同的代碼取決於你試圖改變的對象是字典還是列表。

if type(object)==type([]): 
    for key in range(len(object)): 
     object[key]=1 
elif type(object)==type({}): #use 'else' if you know that object will be a dict if not a list 
    for key in object: 
     object[key]=1