Вы упустили одну возможность:
Определите метод bark
, который вызывает NotImplementedError
, как в вашем варианте 4, но не делает его абстрактным.
Это исключает жалобу PyLint и, что более важно, устраняет законную проблему, на которую он жаловался.
Что касается других ваших вариантов:
hasattr
не требуетсяLBYL, который обычно не является Pythonic. - Проблему
except
можно решить, выполнив bark = self.bark
внутри блока try
, затем выполнив bark()
, если он пройдет.Иногда это необходимо, но тот факт, что это немного неуклюже и не было «исправлено», должен дать вам представление о том, как часто это стоит делать. - Проверка сообщений об ошибках является антишаблоном.Все, что не является отдельным документированным значением аргумента, может быть изменено во всех версиях и реализациях Python.(Плюс, что если
ManWithSidekick.bark()
делает self.sidekick.bark()
? Как бы вы различали AttributeError
там?)
Итак, это оставляет 2, 4.5 и 5.
Я думаю, что в большинстве случаев, 4.5 или 5 будет правильным решением.Разница между ними не прагматичная, а концептуальная: если животное ScaryCat
лает молча, используйте опцию 5;если нет, то лай должен быть необязательной частью защиты, которую делают не все защитники, и в этом случае используйте опцию 4.5.
Для этого игрушечного примера, я думаю, я бы использовал опцию 4.5.И я думаю, что так будет с большинством игрушечных примеров, которые вы придумали.
Однако я подозреваю, что большинство реальных примеров будут довольно разными:
- Большинству реальных примеров не понадобится эта глубокая иерархия.
- Ofте, которые это делают, обычно либо
bark
, либо будут реализованы всеми подклассами, либо не будут вызваны суперклассом. - Из тех, кому это нужно, я думаю, вариант 5 подойдет.Конечно,
bark
в молчании это не то, что делает ScaryCat
, но parse_frame
в молчании это то, что делает ProxyProtocol
. - И после этого осталось так мало исключений, что трудно говоритьо них абстрактно и вообще.