При определении класса дескриптора вы можете просто поднять 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
Это канонический способ решения этой проблемы? Какие ловушки я оставляю для себя, делая это таким образом?
hasattr
ловит ее и возвращаетFalse
. Итак, это вопрос как раз о появлении альтернативных ошибок в случаеhasattr
? - person tdelaney   schedule 20.06.2018hasattr
вместо блока try / except. см., например, методgeometry.asShape
вshapely
библиотеке . - person Rick supports Monica   schedule 20.06.2018__geo_interface__
геттере). - person Rick supports Monica   schedule 20.06.2018AttributeError
иhasattr
будут одним и тем же, я думаю, вы должны это уважать. Создавайте другое исключение только для действительно исключительных условий. Если объект нормальный без атрибута, используйтеAttributeErrror
- если пора собирать вещи и идти домой, поднимите что-нибудь еще. - person tdelaney   schedule 20.06.2018foo
выглядел как атрибут. Я бы сказал, что самое каноничное - сделать так, чтобы он выглядел как можно больше как атрибут. Код, использующийhasattr
, обычно не будет очень изящно обрабатывать какое-либо другое возникшее исключение, и есть большая вероятность, что он сломается, если получит неожиданное исключение. Было бы рискованно поднимать что-либо, если вы действительно не хотите пойти по пути ошибок, который очищает ситуацию. - person tdelaney   schedule 20.06.2018