Ответ 1
Поскольку вы вызываете attr
, вы можете просто сделать:
def default_action():
# do something else
action = getattr(obj, 'attr', default_action)
action()
Я слишком часто делаю следующее:
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
Поскольку вы вызываете attr
, вы можете просто сделать:
def default_action():
# do something else
action = getattr(obj, 'attr', default_action)
action()
Альтернатива try
/except
, как вы ее кодируете, может случайно привести к AttributeError
, вызванному проблемами во всем, что вызывает вызов attr()
. Если вы хотите кодировать с помощью try
/except
, что является разумным и достаточно эффективным, если это редко встречается в атрибуте, используйте:
try:
attr = obj.attr
except AttributeError:
dosome(thingelse)
else:
attr()
это не приведет к "случайному ловушку", как указано выше. Что касается того, какой подход предпочтительнее, я обычно придерживаюсь подхода, основанного на исключении - "EAFP", "проще просить прощения, чем разрешения" (девиз, который часто приписывается адмиралу Грейс Хопперу, движущей силе COBOL и CODASYL), безусловно, применяется хорошо для Python; -).
Есть еще одна приятная идиома:
if hasattr(obj, 'attr'):
...something...
else:
...something else...
Из двух предложенных вами вариантов я предпочитаю первую. Понятие бросания исключений при доступе к членам просто не похоже на то, для чего предназначались исключения.
Подобно Джо отвечает, но короче:
getattr(obj, 'attr', lambda: None)()
Использование try/except обычно считается более pythonic. Это также более эффективно, если obj имеет атрибут, так как он исключает блок тестовых попыток, не имеет накладных расходов, если исключение не выбрасывается. С другой стороны, он менее эффективен, если obj не имеет атрибута, поскольку он будет иметь накладные расходы на выброс и обнаружение исключения.
А, это зависит от точного кода. Ваши два инструмента:
Вот наиболее распространенные случаи:
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'