Как мне лучше структурировать этот код?

У меня есть структура данных lxml.objectify, которую я получаю от веб-службы RESTful. Мне нужно изменить настройку, если она существует, и создать ее, если ее нет. Прямо сейчас у меня есть что-то вроде следующего, но я чувствую, что это уродливо. Структура, которую я ищу, имеет список подэлементов, которые имеют одинаковую структуру, поэтому, к сожалению, я не могу просто искать конкретный тег.

thing_structure = lxml.objectify(get_from_REST_service())
found_thing = False
if thing_structure.find('settings') is not None:
    for i, foo in enumerate(thing_structure.settings):
        if foo.is_what_I_want:
            modify(thing_structure.settings[i])
            found_thing = True
if not found_thing:
    new = lxml.etree.SubElement(thing_structure, 'setting')
    modify(new)

send_to_REST_service(thing_structure)

person Daenyth    schedule 29.09.2010    source источник


Ответы (2)


В целом, структура не так уж плоха (при условии, что вам нужно вызывать modify для 1+ элементов в настройках — если «только один», т. е. если флаг is_what_I_want будет установлен для не более одной настройки, это, конечно, другое, поскольку вы могли бы и должны использовать break из цикла for -- но это не то впечатление о ваших намерениях, которое я получаю от вашего вопроса, пожалуйста, уточните, если я ошибся!). Есть одна избыточность:

for i, foo in enumerate(thing_structure.settings):
    if foo.is_what_I_want:
        modify(thing_structure.settings[i])
        found_thing = True

Иметь i и использовать его для повторного получения того же foo здесь бесполезно, поэтому вы можете упростить до:

for foo in thing_structure.settings:
    if foo.is_what_I_want:
        modify(foo)
        found_thing = True

Индекс понадобится вам только в том случае, если вы будете перепривязывать элемент, т. е. выполнять присваивание, например thing_structure.settings = whatever. (Кстати, имя, отличное от foo, не повредит ;-).

person Alex Martelli    schedule 29.09.2010
comment
Имя foo — это не то, что я использую в реальном коде, я просто пытался немного уменьшить сложность и не добавлять ничего конкретного в свою кодовую базу — больше общей структуры. На самом деле я перепривязываю элемент, поэтому я использовал i. - person Daenyth; 29.09.2010
comment
@Daenyth, foo было довольно очевидно (именно поэтому у меня там был смайлик), но удаление принципиально другой операции перепривязки элемента было чрезмерным упрощением - это действительно имеет значение, делаете ли вы такое перепривязывание (таким образом, нужно enumerate) или не надо (поэтому не нужно). С вашей новой информацией и всегда предполагая, что вам нужно иметь возможность вызывать modify один или более раз (а не только один раз), я не вижу существенного упрощения (некоторые трюки, да, но они могут повредить ясность, а не улучшить ее). - person Alex Martelli; 30.09.2010
comment
Алекс, не могли бы вы взглянуть на это, когда у вас будет возможность: stackoverflow.com/questions/3826473/? Спасибо - person NullUserException; 30.09.2010

Я бы написал это:

thing_structure = lxml.objectify(get_from_REST_service())
if thing_structure.find('settings') is not None:
    foos = [foo for foo in thing_structure.settings if foo.is_what_I_want]
        or [lxml.etree.SubElement(thing_structure, 'setting')]
    for foo in foos:
       modify(foo)
send_to_REST_service(thing_structure)

Я не забочусь о is not None и устраняю его, где могу. Если можно здесь, я бы написал:

if thing_structure.find('settings'):
person hughdbrown    schedule 21.10.2010