Краткий способ получить getattr () и использовать его, если нет в Python - PullRequest
30 голосов
/ 11 марта 2010

Я слишком часто выполняю следующие действия:

attr = getattr(obj, 'attr', None)
if attr is not None:
    attr()
    # Do something, either attr(), or func(attr), or whatever
else:
    # Do something else

Есть ли более питонский способ написания этого? Это лучше? (По крайней мере, не в производительности, ИМО.)

try:
    obj.attr() # or whatever
except AttributeError:
    # Do something else

Ответы [ 6 ]

36 голосов
/ 12 марта 2010

Поскольку вы звоните на attr, вы можете просто сделать:

def default_action():
    # do something else

action = getattr(obj, 'attr', default_action)

action()
12 голосов
/ 17 августа 2014

Аналогично ответу Джо, но короче:

getattr(obj, 'attr', lambda: None)()
7 голосов
/ 12 марта 2010

Альтернатива try / except, как вы ее кодируете, может случайно привести к перехвату AttributeError, вызванному проблемами во всем, что вызывает attr(). Если вы хотите закодировать с помощью try / except, что является разумным и достаточно эффективным, если редко отсутствует атрибут, используйте:

try:
  attr = obj.attr
except AttributeError:
  dosome(thingelse)
else:
  attr()

это не приведет к "случайному отлову", как указано выше. Что касается того, какой подход предпочтительнее, я обычно использую метод ловли исключений: «EAFP», «Проще просить прощения, чем разрешения» (девиз, часто приписываемый адмиралу Грейс Хоппер, движущей силе COBOL и CODASYL), безусловно, применим хорошо Python; -).

7 голосов
/ 11 марта 2010

Есть еще одна приятная идиома:

if hasattr(obj, 'attr'):
    ...something...
else:
    ...something else...

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

1 голос
/ 12 марта 2010

Ах, это зависит от точного кода. Ваши два инструмента:

  • hasattr (obj, 'attr') возвращает True, если и только если существует obj.attr.
  • getattr (obj, 'attr', other_value) возвращает obj.attr, если он существует, иначе other_value
  • try a = obj.attr / кроме fail () / else do_something (a), когда производительность превосходит читабельность.

Вот наиболее распространенные случаи:

 the_name = getattr(user, 'name', '<Unknown User>')
 user.name = getattr(user, 'name', '<Unknown User>')
 if not hasattr(name, 'user'):
    try_asking_again()
 name = user.name if hasattr(user, 'name') else do_expensive_name_lookup(user)

Чтобы лучше понять весь процесс, посмотрите на этот фрагмент:

class Thing():
    def __init__(self):
        self.a = 'A'

    def __getattr__(self, attr):
        if attr == "b":
            return "B"
        else:
            raise AttributeError("Thing instance has no attribute '" + attr + "'")

item = Thing()
print "hasattr(a) is " + str(hasattr(item, "a"))
print "a is " + item.a
print "hasattr(b) is " + str(hasattr(item, "b"))
print "b is " + item.b
out = "c is " + item.c if hasattr(item, "c") else "No C"
print out
print "and c is also " + getattr(item, "c", "Not Assigned")
print "c throws an Attribute exception " + item.c

который имеет этот вывод:

hasattr(a) is True
a is A
hasattr(b) is True
b is B
No C
and c is also Not Assigned
Traceback (most recent call last):
  File "attr_snippet.py", line 23, in <module>
    print "c throws an Attribute exception " + item.c
  File "attr_snippet.py", line 9, in __getattr__
    raise AttributeError("Thing instance has no attribute '" + attr + "'")
AttributeError: Thing instance has no attribute 'c'
1 голос
/ 12 марта 2010

Использование try / кроме обычно считается более питоническим. Это также более эффективно, если obj действительно имеет атрибут, так как он устраняет блоки test - try без издержек, если исключение не выдается. С другой стороны, он менее эффективен, если у obj нет атрибута, так как он будет перегружен генерацией и перехватом исключения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...