Как параметризовать общий модуль Python?

Могу ли я создать модуль, использующий функции, которые будут предоставлены импортерами модуля?

Я хочу написать общий код без указания реализации нескольких ключевых функций. Я хочу, чтобы пользователь указал их. Я мог бы включить их в качестве входных данных для всех функций, но это выглядит некрасиво.

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

Изменить: я конкретно спрашиваю о том, как это сделать с помощью функций в модулях, а не методов в классах.


person MRocklin    schedule 13.09.2012    source источник
comment
Что-то вроде stackoverflow.com/questions/3928023/ возможно?   -  person Silas Ray    schedule 13.09.2012
comment
Когда вы говорите, что хотите, чтобы пользователь задавал функции, вы хотите, чтобы он сделал это один раз и использовал их на протяжении всей программы, или чтобы динамически использовать разные функции в зависимости от контекста, из которого вызывается ваш динамический модуль?   -  person Silas Ray    schedule 13.09.2012
comment
Почему вы специально хотите сделать это с функциями в модулях? Кажется, что для вашего варианта использования гораздо проще использовать классы вместо модулей.   -  person Hans Then    schedule 13.09.2012


Ответы (2)


Можно исправить модуль и добавить новые функции в модуль во время выполнения.

import my_module
def my_implementation():
    pass

my_module.implementation = my_implementation

Однако это осуждается в сообществе Python. Он по своей сути нестабилен, так как это повлияет на всех пользователей этого модуля. Например, если вы используете другой модуль, который также использует модуль, который вы заплатили обезьяной, ваш другой модуль может демонстрировать ошибочное поведение, которое трудно отладить.

Для того, что вы хотите сделать, вам лучше создать абстрактный класс :-)

person Hans Then    schedule 13.09.2012
comment
Просто обычный класс с несколькими отсутствующими методами. - person Hans Then; 13.09.2012
comment
@Tichodroma, как говорит Ганс, вы можете создать обычный класс с несколькими отсутствующими методами (или, лучше, с несколькими методами, которые вызывают NotImplementedError). Однако есть также ABC (абстрактный базовый класс), или вы можете создать свою собственную систему абстрактных классов с помощью метаклассов. - person Silas Ray; 13.09.2012
comment
См. docs.python.org/library/abc.html для абстрактных базовых классов. Однако абстрактные базовые классы действительно излишни для того, что вы хотите сделать. См. обоснование абстрактных базовых классов здесь: python.org/dev/peps/pep- 3119 - person Hans Then; 13.09.2012
comment
Я думаю, что заплатка обезьяны - это просто идеальный ответ, когда вы хотите знать, что произойдет (с точки зрения эффективности памяти и времени), если вы измените реализацию некоторого типа данных. Вы можете написать новую реализацию в скрытом модуле и подключить его, чтобы сравнить тайминги и использование памяти. - person Bakuriu; 13.09.2012
comment
monkeypatching работает, но он не является динамическим или предсказуемым, и он определенно не автоматический... Интересно, можно ли построить фабрику, которая будет создавать прокси для заданного модуля, а затем вставлять это в sys.modules вместо самого объекта модуля, так что вы можете динамически и автоматически подтягивать функции к экземпляру прокси-сервера модуля, указанному в пространстве имен импорта, при импорте... - person Silas Ray; 13.09.2012
comment
Не слишком ли это? Читая пост, я задаюсь вопросом, зачем вам это делать, когда гораздо проще перепроектировать ваш модуль для использования классов. - person Hans Then; 13.09.2012

Если вы сделаете это в модуле, у вас возникнет проблема, если когда-нибудь в той же программе один модуль захочет использовать ваш общий модуль с реализацией, а другой модуль захочет использовать его с другим.

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

Посмотрите в "случайном" модуле, например. Все функции модуля, такие как «randint», «uniform», «gauss», фактически привязаны к методу скрытого экземпляра класса random.Random. Но вы также можете использовать свой собственный экземпляр класса Random или создать его подкласс, переопределив несколько ключевых методов, чтобы изменить способ генерации random, но сохранить все полезные методы.

См. http://docs.python.org/library/random.html.

person MatthieuW    schedule 13.09.2012