Я пишу свой собственный контейнер, который должен предоставлять доступ к словарю внутри с помощью вызовов атрибутов. Типичное использование контейнера будет выглядеть так:
dict_container = DictContainer()
dict_container['foo'] = bar
...
print dict_container.foo
Я знаю, что было бы глупо писать что-то подобное, но это функциональность, которую я должен предоставить. Я думал о реализации этого следующим образом:
def __getattribute__(self, item):
try:
return object.__getattribute__(item)
except AttributeError:
try:
return self.dict[item]
except KeyError:
print "The object doesn't have such attribute"
Я не уверен, являются ли вложенные блоки try / кроме хорошей практики, поэтому другим способом было бы использовать hasattr()
и has_key()
:
def __getattribute__(self, item):
if hasattr(self, item):
return object.__getattribute__(item)
else:
if self.dict.has_key(item):
return self.dict[item]
else:
raise AttributeError("some customised error")
Или использовать одну из них и одну попытку блока catch, например:
def __getattribute__(self, item):
if hasattr(self, item):
return object.__getattribute__(item)
else:
try:
return self.dict[item]
except KeyError:
raise AttributeError("some customised error")
Какой вариант является наиболее питонным и элегантным?
if 'foo' in dict_container:
. Аминь.Ответы:
Ваш первый пример совершенно в порядке. Даже официальные документы Python рекомендуют этот стиль, известный как EAFP .
Лично я предпочитаю избегать вложения, когда в этом нет необходимости:
PS.
has_key()
долгое время считалось устаревшим в Python 2. Используйтеitem in self.dict
вместо этого.источник
return object.__getattribute__(item)
неверно и приведетTypeError
к неправильному количеству передаваемых аргументов. Так должно бытьreturn object.__getattribute__(self, item)
.from None
означает в последней строке?Хотя в Java действительно плохая практика использовать исключения для управления потоком (главным образом потому, что исключения заставляют jvm собирать ресурсы ( подробнее здесь )), в Python у вас есть два важных принципа: Duck Typing и EAFP . В основном это означает, что вам рекомендуется использовать объект так, как вы думаете, он будет работать, и обращаться с ним, когда все не так.
Подводя итог, можно сказать, что единственной проблемой будет слишком большой отступ кода. Если вам так хочется, попробуйте упростить некоторые из вложений, например, предложенных lqc.
источник
Для вашего конкретного примера вам не нужно их вкладывать. Если выражение в
try
блоке выполнится успешно, функция вернется, поэтому любой код после всего блока try / Кроме того, будет выполнен только в случае неудачной первой попытки. Так что вы можете просто сделать:Вложение их не плохо, но я чувствую, что если оставить все как есть, структура станет более понятной: вы последовательно пробуете ряд вещей и возвращаете первый, который работает.
Кстати, вы можете подумать о том, действительно ли вы хотите использовать
__getattribute__
вместо__getattr__
здесь. Использование__getattr__
упростит вещи, потому что вы будете знать, что нормальный процесс поиска атрибутов уже потерпел неудачу.источник
Только будьте осторожны - в этом случае сначала
finally
дотрагивается, НО пропускается тоже.источник
finally
блока выполняютсяa(0)
, ноfinally-return
возвращается только родитель .На мой взгляд, это был бы самый Pythonic способ справиться с этим, хотя и потому, что это делает ваш вопрос спорным. Обратите внимание, что это определяет
__getattr__()
вместо того,__getattribute__()
потому что это означает, что он имеет дело только со «специальными» атрибутами, хранящимися во внутреннем словаре.источник
except
блоке может привести к сбивающим с толку выводам в Python 3. Это потому, что (согласно PEP 3134) Python 3 отслеживает первое исключение (theKeyError
) как «контекст» второго исключения (theAttributeError
), и если оно достигает верхний уровень, он напечатает трассировку, которая включает оба исключения. Это может быть полезно, когда второе исключение не ожидалось, но если вы намеренно повышаете второе исключение, это нежелательно. Для Python 3.3 в PEP 415 добавлена возможность подавления контекста с помощьюraise AttributeError("whatever") from None
.KeyError
вAttributeError
и показывает, что то, что произошло в трассировке, было бы полезно и уместно.__getattr__
возникает исключение, ошибка, вероятно, является опечаткой в доступе к атрибуту, а не ошибкой реализации в коде текущего класса. Отображение более раннего исключения в качестве контекста может запутать это. И даже когда вы подавляете контекст с помощьюraise Whatever from None
, вы все равно можете получить предыдущее исключение при необходимости черезex.__context__
.__getattribute__()
.В Python проще просить прощения, чем разрешения. Не беспокойтесь о вложенной обработке исключений.
(Кроме того,
has*
почти всегда в любом случае используются исключения под прикрытием.)источник
Согласно документации , лучше обрабатывать множественные исключения через кортежи или вот так:
источник
Хороший и простой пример для вложенного try / кроме может быть следующим:
Теперь попробуйте различные комбинации, и вы получите правильный результат:
[конечно, у нас есть numpy, поэтому нам не нужно создавать эту функцию]
источник
Одна вещь, которую мне нравится избегать, - вызывать новое исключение при обработке старого. Это делает сообщения об ошибках запутанными для чтения.
Например, в моем коде я изначально написал
И я получил это сообщение.
То, что я хотел, было это:
Это не влияет на то, как обрабатываются исключения. В любом блоке кода KeyError был бы пойман. Это просто вопрос получения очков стиля.
источник
from None
хотя, для еще большего количества стилей. :)Если попытка-исключить-наконец-то вложена в блок, наконец, результат "потомок", наконец, сохраняется. Я еще не нашел официального объяснения, но следующий фрагмент кода демонстрирует это поведение в Python 3.6.
источник
Я не думаю, что дело в том, чтобы быть питоническим или элегантным. Это вопрос предотвращения исключений настолько, насколько это возможно. Исключения предназначены для обработки ошибок, которые могут возникнуть в коде или событиях, которые вы не можете контролировать. В этом случае вы имеете полный контроль при проверке, является ли элемент атрибутом или в словаре, поэтому избегайте вложенных исключений и придерживайтесь второй попытки.
источник