Я пытаюсь найти хороший способ записать предупреждающее сообщение, но добавляю к нему информацию, известную только вызывающей функции.
Я думаю, это будет понятно на примере.
# log method as parameter
class Runner1(object):
def __init__(self, log):
self.log = log
def run(self):
self.log('First Warning')
self.log('Second Warning')
return 42
class Main1(object):
def __init__(self):
self._runner = Runner1(self.log)
def log(self, message):
print('Some object specific info: {}'.format(message))
def run(self):
print(self._runner.run())
e1 = Main1()
e1.run()
Главный объект имеет функцию журнала, которая добавляет к любому сообщению свою собственную информацию перед его регистрацией. Эта функция журнала задается как параметр (в данном случае для объекта Runner). Ношение этого дополнительного параметра все время чрезвычайно раздражает, и я хотел бы избежать этого. Обычно есть много объектов / функций, и поэтому я отказался от использования метода ведения журнала, так как мне нужно было бы создать разные средства ведения журнала для каждого объекта. (Это правильно?)
Я попытался выдать предупреждение с помощью модуля предупреждения:
# warning module
import warnings
class Runner2(object):
def run(self):
warnings.warn('First Warning')
warnings.warn('Second Warning')
return 42
class Main2(object):
def __init__(self):
self._runner = Runner2()
def log(self, message):
print('Some object specific info: {}'.format(message))
def run(self):
with warnings.catch_warnings(record=True) as ws:
warnings.simplefilter("always")
out = self._runner.run()
for w in ws:
self.log(w.message)
print(out)
e2 = Main2()
e2.run()
Но, согласно документации, это не безопасно для потоков.
Наконец, я также попробовал некоторые генераторы:
# yield warning
class _Warning(object):
def __init__(self, message):
self.message = message
class Runner3(object):
def run(self):
yield _Warning('First Warning')
yield _Warning('Second Warning')
yield 42
class Main3(object):
def __init__(self):
self._runner = Runner3()
def log(self, message):
print('Some object specific info: {}'.format(message))
def run(self):
for out in self._runner.run():
if not isinstance(out, _Warning):
break
self.log(out.message)
print(out)
e3 = Main3()
e3.run()
Но тот факт, что вам нужно изменить Runner.run, чтобы получить (вместо возврата) конечный результат, неудобен, так как функции должны быть специально изменены для использования таким образом (возможно, это изменится в будущем? Последний QA в PEP255 ). Кроме того, я не уверен, есть ли какие-либо другие проблемы с этим типом реализации.
Итак, я ищу поточно-ориентированный способ вывода предупреждений, который не требует передачи параметров. Также хотелось бы, чтобы методы, у которых нет предупреждений, остались без изменений. Добавление специальной конструкции, такой как yield или warning.warn, для всплытия предупреждений будет в порядке.
Есть идеи?