Подтвердить что ты не робот

Pythonic способ присвоить значения по умолчанию

Рассмотрим эту строку:

some_value = lst.attr[idx]

Здесь возможны две ошибки: attr может не существовать, а idx может быть вне диапазона.

Есть ли элегантный способ уменьшить это утверждение? В идеале, что-то вроде этого:

some_value = lst.attr[idx] or default_value

(Не пытайтесь делать это дома, это работает только для правильно определенных выражений, которые что-то оценивают.)

Конечно, я могу сделать:

try:
    some_value = lst.attr[idx]
except:
    some_value = default_value

Но что, если я в контексте задания? Например:

print [x.attr[idx] for x in y]

Какой питонический способ обрабатывать ошибки и назначать значения по умолчанию в этом случае?

4b9b3361

Ответ 1

Вам нужно решить, чего вы пытаетесь достичь здесь. Использование слова "ошибка", вероятно, вводит в заблуждение.

Если вы на самом деле пытаетесь обработать случай, когда неправильный тип объекта передается вашей функции, вы не хотите обрабатывать его и должны возбуждать исключение.

Если вы пытаетесь разрешить использование вашей функции в серии разных типов, то это не означает, что ошибка и использование значения по умолчанию могут быть разумными.

Самый простой вариант - проверить, существует ли атрибут в первую очередь. Например:

if hasattr(lst, "attr"):
    attr = lst.attr
else:
    attr = {}

Я предполагаю, что lst.attr - это словарь, и в этом случае вы можете обрабатывать значение по умолчанию так:

lst.attr.get(idx, default_value)

Никогда не используйте инструкцию try/except, где вы не указываете, какое исключение вы ловите. Вы можете в конечном итоге маскировать гораздо больше, чем вы планировали.

С вашей последней частью кода я думаю, вы не должны пытаться решить ее в одной строке. Показатели удобочитаемости. Я недоволен приведенным ниже кодом, но это было бы улучшено, если бы были заменены x, y и attr на более описательные имена.

attrs = [(x.attr if hasattr(x) else {}) for x in y]

print [attr.get(idx, default_value) for attr in attrs]

Ответ 2

Какой питонический способ обрабатывать ошибки и назначать значения по умолчанию в этом случае?

>>> import this
...
Explicit is better than implicit.
...
Sparse is better than dense.
Readability counts.
...
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.

У меня такое ощущение, что " Pythonic способ присвоить значения по умолчанию" * - это либо обработать исключение, как вы уже упоминали в своем вопросе, либо написать свои собственные геттеры.

Ответ 3

написать функцию и сделать ее достаточно умной:

def get_attr_with_index_and_default(obj, attr_name, index, default):
    try:
        return getattr(obj, attr_name)[index]
    except (AttributeError, IndexError):
         return default

print [get_attr_with_index_and_default(x, 'attr', idx, some_default) for x in y]

если вы управляете классом x, вы можете использовать это как метод или адаптировать его как дескриптор, но imo это не стоит и приведет к неясному коду и затруднит отслеживание ошибок.

Ответ 4

Даже если существует однострочный, это будет очень сложно. Например. это еще не справляется с проблемой индекса:

some_value = getattr(lst, 'attr', {idx: default_value})[idx]

Я бы предложил написать некоторый getter для вашего lst.

Ответ 5

Когда в объекте есть "attr"

class C(object):
    attr = "attr on class"
lst = C()
print lst.attr if hasattr(lst,'attr') else "default value"

Если атрибут 'attr'

отсутствует,
class C(object):
    #attr = "attr on class"
    pass
lst = C()
print lst.attr if hasattr(lst,'attr') else "default value"

Ответ 6

Нет простого и элегантного решения вашей проблемы. Если это необходимо сделать с помощью однострочного интерфейса, который может использоваться, например, в использовании списков, то вы можете сделать следующее:

# If lst.attr is a dict.
some_value = getattr(lst, 'attr', {}).get(idx, default_value)
# OR
some_value = lst.attr.get(idx, default_value) if hasattr(lst, 'attr') else default_value
# OR
some_value = lst.attr[idx] if hasattr(lst, 'attr') and idx in lst.attr else default_value

# If lst.attr is a sequence.
some_value = lst.attr[idx] if idx < len(getattr(lst, 'attr', ())) else default_value
# OR
some_value = lst.attr[idx] if hasattr(lst, 'attr') and idx < len(lst.attr) else default_value