Как динамически генерировать функции в Python

Можно ли динамически генерировать методы классов, которые очень похожи друг на друга?

Скажем, у меня есть такой класс:

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) метод публичного общения и продолжать свою жизнь. Справедливо. Но больше, чем разумное решение, меня интересует здесь мельчайшая проблема.)

Спасибо!

Просто используйте решение в последнем абзаце. Создание динамических функций возможно, но нет причин использовать их здесь (или, на самом деле, это подавляющее большинство, если не все обстоятельства). Для создания функций вы могли бы использовать что-то вроде eval, но это был бы просто хакерский способ эмуляции параметра.

Carcigenicate 28.04.2024 16:24

Там много вопросов SO с ответами, возвращаемыми простым поиском Google «динамическое создание метода Python», что именно в них не ответило на ваш вопрос?

Thierry Lathuille 28.04.2024 16:37

Вы можете переопределить getattr, но это будет большой проблемой, если вы сможете просто использовать параметр.

CrazyChucky 28.04.2024 16:43

В Python это возможно и не страшно (без eval), но лучше не использовать динамические возможности Python — статический анализ (как инструментами, так и людьми) очень ценен. Я бы составил список повторяющихся методов, предполагая, что на самом деле они настолько просты.

Ry- 28.04.2024 16:45
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
4
79
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Да, это возможно, но это может быть жестко отлаживаемый подход. Для этих целей вы можете использовать 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 без скобок.

Как вы думаете, это решит вашу проблему? Если да, я могу это объяснить

Определенно хороший пример!

Dmitry Brazhenko 28.04.2024 19:07

@ДмитрийБраженко, этот ответ хуже твоего. Здесь методы не будут отображаться в dir(KintchenDrawer) или help(KintchenDrawer).

Joooeey 28.04.2024 19:29

Да, это не будет отображаться, но с другой стороны, это обеспечивает большую гибкость.

Dmitry Brazhenko 29.04.2024 09:22

Другие вопросы по теме