Итерации по типу или списку в Python
Просто написал какой-то неприятный код, который выполняет итерацию по dict
или list
в Python. У меня такое чувство, что это не лучший способ.
Проблема заключается в том, что для итерации по dict это соглашение:
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
Есть ли лучший способ сделать это?
Спасибо!
Ответы
Ответ 1
Мне никогда не приходилось это делать, когда-либо. Но если бы я это сделал, я бы, наверное, сделал что-то вроде этого:
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}
Ответ 2
Это правильный путь, но если по какой-то причине вам нужно обращаться с этими двумя объектами одинаково, вы можете создать итерабельность, которая будет возвращать индексы/ключи независимо от того, что:
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
Ответ 3
Чтобы быть pythonic и 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)
Ответ 4
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]
Ответ 5
Вероятно, вы просто хотите иметь другой код в зависимости от того, будет ли объект, который вы пытаетесь изменить, - это dict или список.
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