Можно ли динамически генерировать методы классов, которые очень похожи друг на друга?
Скажем, у меня есть такой класс:
class KitchenDrawer:
def _check_if_tool_available(self, tool) -> bool:
# check if "tool" is in the drawer
def is_knife_available(self) -> bool:
return self._check_if_tool_available("knife")
def is_spoon_available(self) -> bool:
return self._check_if_tool_available("spoon")
def is_fork_available(self) -> bool:
return self._check_if_tool_available("fork")
Есть ли способ динамически генерировать is_knife_available()
, is_spoon_available()
, is_fork_available()
, чтобы не было так много повторяющегося кода?
(Некоторые из вас могут предложить просто сделать _check_if_tool_available(self, tool)
метод публичного общения и продолжать свою жизнь. Справедливо. Но больше, чем разумное решение, меня интересует здесь мельчайшая проблема.)
Спасибо!
Там много вопросов SO с ответами, возвращаемыми простым поиском Google «динамическое создание метода Python», что именно в них не ответило на ваш вопрос?
Вы можете переопределить getattr, но это будет большой проблемой, если вы сможете просто использовать параметр.
В Python это возможно и не страшно (без eval
), но лучше не использовать динамические возможности Python — статический анализ (как инструментами, так и людьми) очень ценен. Я бы составил список повторяющихся методов, предполагая, что на самом деле они настолько просты.
Да, это возможно, но это может быть жестко отлаживаемый подход. Для этих целей вы можете использовать setattr()
.
Например, вы можете реализовать что-то вот так:
class KitchenDrawer:
def _check_tool(self, tool):
return tool in ['knife', 'spoon', 'fork']
for tool in ['knife', 'spoon', 'fork']:
setattr(KitchenDrawer, f'is_{tool}_available', lambda self, t=tool: self._check_tool(t))
# Usage
drawer = KitchenDrawer()
print(drawer.is_knife_available()) # True
Также вы можете проверить, что в классе доступны методы is_fork_available
, is_knife_available
, is_spoon_available
:
dir(KitchenDrawer)
# [... 'is_fork_available', 'is_knife_available', 'is_spoon_available']
Вот вопрос, связанный с , который может быть полезен при использовании лучшего подхода.
class KintchenDrawer:
def __getattr__(self, attr: str):
if res := re.findall("is_(\w*?)_available", attr):
return self._check_if_tool_available(res[0])
Тогда вы можете использовать self.is_spoon_available
без скобок.
Как вы думаете, это решит вашу проблему? Если да, я могу это объяснить
Определенно хороший пример!
@ДмитрийБраженко, этот ответ хуже твоего. Здесь методы не будут отображаться в dir(KintchenDrawer)
или help(KintchenDrawer)
.
Да, это не будет отображаться, но с другой стороны, это обеспечивает большую гибкость.
Просто используйте решение в последнем абзаце. Создание динамических функций возможно, но нет причин использовать их здесь (или, на самом деле, это подавляющее большинство, если не все обстоятельства). Для создания функций вы могли бы использовать что-то вроде
eval
, но это был бы просто хакерский способ эмуляции параметра.