Я думаю об этом в течение некоторого времени с несколькими примерами, и я искренне думаю, что было бы удобно напрямую ссылаться на объект-метод изнутри кода метода или, вообще говоря: ссылаться на пространство имен изнутри.Давайте посмотрим на мой текущий код:
def do_stuff(args):
logtarget, someargs = process_input(args)
processed_data = do_other_stuff(someargs, outputdir)
log("Template string".format(processed_data), outputdir=outputdir, filename="resultfile.txt")
def do_other_stuff(someargs, logtarget):
step = process_data(someargs)
if requires_manual_postproceccing(step):
log(step, outputdir=outputdir, filename="handle manually.txt")
return get_result(step)
def log(message, outputdir="default", filename="default.txt"):
with open("{}/{}".format(outputdir, filename), "a") as file:
file.write(message)
Как вы можете видеть, я довольно часто передаю outputdir, и я даже не упомянул, что do_stuff и do_other_stuff могут также регистрировать события (но так какМне не нужны эти журналы, пока скрипт работает нормально, меня не волнует его местоположение).Разве не было бы хорошо, если бы кто-то мог установить параметр один раз и затем получить доступ к нему в сообщении журнала?Цель обрабатывается сценарием, поэтому я не могу жестко закодировать ее.
Поскольку outputdir обрабатывается в функции (пространстве имен), мы не можем получить к нему доступ из других функций (пространств имен), если не используем glogal
ключевое слово, что - после всего, что я прочитал об этом - я надеялся никогда не использовать.Мои интуиции говорят мне, чтобы я справился с этой проблемой следующим образом:
def do_stuff(args):
outputdir, someargs = process_input(args)
log.outputdir = outputdir
processed_data = do_other_stuff(someargs)
log(processed_data.format("somehow"), filename="resultfile.txt")
def do_other_stuff(someargs):
step = process_data(someargs)
if requires_manual_posproceccing(step):
log(step, filename="handle manually.txt")
return get_result(step)
def log(message, filename="default.txt"):
with open("{}/{}".format(this.outputdir, filename), "a") as file:
file.write(message)
Его легче читать, он использует меньше аргументов и не вызывает странного поведения и ошибок - но это явно не работает.Теперь я знаю, что могу (должен?) Использовать необычную библиотеку журналов или, по крайней мере, написать класс logger, чтобы я мог использовать logger = Logger(outputdir)
, а затем использовать self
внутри методов.Но сохранять его стройным и плоским - это способ программирования на Python, и до сих пор я мог легко следовать правилу: «Всякий раз, когда вы видите класс с одним методом, отличным от __init__
, он должен быть просто функцией».Кроме того, даже когда я использовал этот класс регистратора или библиотеку журналирования, мне все равно приходилось передавать его экземпляр.
Это лучший способ справиться с этим, используя имя метода вместо this
и рискуют проблемы, когда кто-то украшает мои функции или есть способ напрямую ссылаться на текущее пространство имен и его атрибуты?Либо я не знаю подходящих слов для поиска, либо это слишком низкий уровень для документирования, либо он не существует.
[Edit:] На самом деле, что я действительно хотел сделать (ноне знал, что я хотел это), чтобы украсить (oop-cecorate, в отличие от Python-decorate) функцию log
.Но все же я столкнулся бы с той же проблемой, поскольку log = decorate(log)
будет влиять только на текущее пространство имен.dir
возвращает текущее пространство имен, а не глобальное, поэтому, если вы не хотите использовать global
, на самом деле нет другого пути, кроме как создать и передать вызываемый объект (callbackfunction).Прямо сейчас есть два ответа, и я не мог легко решить, какой из них яснее.Класс вызываемого , предложенный Мартином Боннером , работает со стандартным Python и создает только один вызываемый элемент вместо двух.С другой стороны, решение, которое я выбрал, - это get_log
-функция, которая возвращает функцию, поскольку она еще более понятна, избегает создания класса только с одним методом, отличным от __init__
, и требует меньше кода:
def get_log(outerdir):
def log(message, filename="default.txt"):
with open("{}/{}".format(outputdir, filename), "a") as file:
file.write(message)
return log
Если мы сделаем это более общим, создав круговой декоратор, который можно добавить к любой функции, мы просто воссоздадим partial
функцию , предложенную heemayl , и мы приступим.Наиболее питонский подход не изобретен здесь и использует наименьший код.