#python #package #built-in #monkeypatching #shadowing
#python #пакет #встроенный #monkeypatching #затенение
Вопрос:
У меня есть пакет Python с десятками подпакетов / модулей. Почти каждый из модулей использует open
встроенную функцию Python. Я написал собственную реализацию функции открытия файла и хотел бы «перенаправить» все open
вызовы, которые у меня есть в модулях пакета, на my_open
функцию.
Я знаю, что можно написать open = my_open_file
в верхней части модуля, чтобы затенить open
внутри модуля, но это означало бы редактирование каждого модуля. Альтернативно, поместить open = my_open_file
в __init__.py
часть пакета и затем выполнить from package_name import open
, что также подразумевает добавление одной строки кода к каждому модулю.
Можно ли определить my_open_file
функцию для области видимости пакета только в одном месте? Или добавление одной строки кода в каждый модуль — мой единственный вариант?
Ответ №1:
Подумайте о том, что вы просите сделать с этим модулем: вы написали свой собственный пакет, личное изменение способа связи встроенной функции. Вы хотите переопределить стандартную языковую функцию. Это нормально … часть мощи языка — это возможность делать вещи так, как вы определяете.
Проблема возникает, когда вы хотите сделать это по умолчанию, переопределяя эту стандартную возможность для кода, который явно не запрашивал это изменение. Вы не можете этого сделать без каких-либо мощных полномочий. Самый простой способ — перестроить вашу систему Python из исходных текстов, заменив стандарт open
на свой собственный.
На самом деле, «обычный» способ заключается в том, чтобы каждый из ваших прикладных модулей «включился», явно заявив, что он хочет использовать новый open
вместо того, который определен языком. Это подход, который вы изложили во втором абзаце. Как это проблема для вас? Вставка строки в каждый из списка параметризованных файлов — это одна системная команда.
Комментарии:
1. Спасибо за сообщение, полезно. Я не возражаю против редактирования кода, это не проблема. Мне просто интересно, поддерживает ли Python перезапись встроенной функции в одном месте, а затем делает ее доступной для всего пакета. Из любопытства, можно ли сделать пользовательскую функцию доступной во всех модулях всего пакета без импорта в каждый модуль (функция,
my_open_file
определенная в каком-либо модуле или__init__.py
)?2. Да, но так же, как и при перезаписи, вам нужно перестроить интерпретатор Python, чтобы присвоить вашему дополнению статус «встроенный». Имейте в виду, что вы просите изменить определение языка : вы пытаетесь подрезать механизм, определенный именно для вашей проблемы, и сделать ваши изменения частью стандартных пакетов.
3. Я немного боюсь, что если я неясно обратился за помощью — функция, которую я написал, это просто оболочка вокруг встроенного
open
— она написана на Python, а не C. Меняет ли это что-нибудь в ваших ответах на мои вопросы?4. Нет, это ничего не меняет, за исключением очевидного расширения необходимых шагов перекомпиляции для изменения этого определения.
Ответ №2:
Очень аккуратный способ сделать то, что вы просите, — использовать builtins
module
имя во время переопределения:
import builtins
_open = builtins.open
def override(*args, **kwargs):
# do whatever before or after open
return _open(*args,**kwargs)
builtins.open = override
Убедитесь, что это выполняется раньше всего, возможно, поместив его в свой пакет __init__.py
, и у вас будет желаемая функциональность с нулевыми дополнительными затратами, никаких других строк не требуется, только один импорт в любом месте вашего кода. Конечно, обратите внимание, что, если, например, вы запускаете код внутри IDE, IDE, скорее всего, попытается импортировать ваш модуль, что приведет к тому, что IDE также будет использовать модифицированную open
функцию.