Канонический способ обработки ошибки AttributeError, возникающей внутри дескриптора

При определении класса дескриптора вы можете просто поднять AttributeError, чтобы указать, что атрибут недоступен. Например:

from typing import Any, TypeVar, MutableMapping

V = TypeVar("V")

class Desc:
    def __init__(self, key: str) -> None:
        self.key = key
    def __get__(self, instance: Any, owner: type) -> V:
        try:
            return instance._dict[self.key]
        except KeyError:
            raise AttributeError()

class C:
    foo = Desc("d")
    def __init__(self, d: MutableMapping[str, V]) -> None:
        self._dict = d

Используйте как:

>>> d1 = dict(d=0, bar=0, baz=0)
>>> c = C(d1)
>>> c.foo 
0
>>> d1.update(d=1)
>>> c.foo
1
>>> hasattr(C(dict()), "foo")
False

Обратите внимание на то, что AttributeError заставляет функцию hasattr "тихо терпеть неудачу". Это ожидаемо и описано в протоколе дескриптора.

Однако в некоторых случаях может потребоваться, чтобы AttributeError «всплыл» наверх. Например:

class NewDesc:
    def __get__(self, instance, owner):
        do_complex_task(instance) # <-- AttributeError occurs here
        return instance._on_the_fly_private_attr

Я обнаружил, что с этим легко справиться, заключив некорректную строку кода в блок try-except, который вызывает другую ошибку, отличную от AttributeError:

try:
    do_complex_task(instance) # <-- AttributeError occurs here
except AttributeError as e:
    raise MyError() from e

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


person Rick supports Monica    schedule 20.06.2018    source источник
comment
Ошибка действительно всплывает - просто hasattr ловит ее и возвращает False. Итак, это вопрос как раз о появлении альтернативных ошибок в случае hasattr?   -  person tdelaney    schedule 20.06.2018
comment
@tdelaney это не совсем так просто - я заметил, что другие библиотеки довольно часто используют блок if / else hasattr вместо блока try / except. см., например, метод geometry.asShape в shapely библиотеке .   -  person Rick supports Monica    schedule 20.06.2018
comment
@tdelaney, однако, в этом случае, действительно не будет иметь большого значения, чтобы изменить, чтобы попробовать / кроме. во всяком случае, именно этот фрагмент кода укусил меня сегодня утром и заставил задуматься об этом (тихий сбой в моем __geo_interface__ геттере).   -  person Rick supports Monica    schedule 20.06.2018
comment
Интересный вопрос. Поскольку программы ожидают, что AttributeError и hasattr будут одним и тем же, я думаю, вы должны это уважать. Создавайте другое исключение только для действительно исключительных условий. Если объект нормальный без атрибута, используйте AttributeErrror - если пора собирать вещи и идти домой, поднимите что-нибудь еще.   -  person tdelaney    schedule 20.06.2018
comment
@tdelaney имеет смысл. Я думаю, это был не очень хороший вопрос, но мне было интересно, есть ли общепринятый способ, плавающий там.   -  person Rick supports Monica    schedule 20.06.2018
comment
Вы используете дескриптор, потому что хотите, чтобы foo выглядел как атрибут. Я бы сказал, что самое каноничное - сделать так, чтобы он выглядел как можно больше как атрибут. Код, использующий hasattr, обычно не будет очень изящно обрабатывать какое-либо другое возникшее исключение, и есть большая вероятность, что он сломается, если получит неожиданное исключение. Было бы рискованно поднимать что-либо, если вы действительно не хотите пойти по пути ошибок, который очищает ситуацию.   -  person tdelaney    schedule 20.06.2018
comment
@tdelaney да, это и моя мысль: поднимайте что-нибудь еще, только если вы ХОТИТЕ, чтобы это прекратилось. Было бы хорошо, если бы существовал способ вызвать ошибку атрибута, которая сигнализирует механизму дескриптора о том, что произошло что-то плохое, и отличить это от обычной ошибки атрибута. не уверен, как можно заставить это работать в языке.   -  person Rick supports Monica    schedule 21.06.2018
comment
@tdelaney, кажется, я не первый, кто осознает, что это действительно проблема: stackoverflow.com/a/1063055/2437514   -  person Rick supports Monica    schedule 21.06.2018