Monkeypatching logging.Logger как работают аргументы?

У меня есть класс ведения журнала, который я написал, и мне нравится его использовать. Это выглядит так:

class EasyLogger(object):
    SEP = " "

    def __init__(self, logger=logging.getLogger(__name__)):
        self.logger = logger

    def _format_str(self, *args):
        return self.SEP.join([str(a) for a in args])

    def debug(self, *args):
        self.logger.debug(self._format_str(*args))

    .... repeated for the other logging methods, like info, warning, etc....

    def __getattr__(self, name):
        return getattr(self.logger, name)

Это дает мне синтаксис вроде:

LOG.debug("some_variable: ", some_variable)

который я хотел. Я не хочу наследовать от logging.Logger, потому что композиция лучше, чем наследование, и я действительно не хочу возиться с подобными встроенными классами.

Моя строка формата выглядит так:

LOGGING_FMT = "<%(filename)s:%(lineno)s(%(levelname)s) - %(funcName)s() >"\
                        "%(message)s"

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

Я исправил эту проблему, следуя этому фантастический ответ и исправление findCaller метода EasyLogger.logger, который выглядит так:

def __init__(self, logger=logging.getLogger(__name__)):
    self.logger = logger
    # Ugly, ugly, ugly dirty hack to fix line numbers
    self.logger.findCaller = find_caller_monkeypatch

Это работает, но я в замешательстве. Первоначально я определил find_caller_monkeypatch со следующей подписью:

def find_caller_monkeypatch(self):

(тело функции копируется + вставляется из связанного ответа). Однако это вызывает ошибку:

  File "/usr/lib64/python2.7/logging/__init__.py", line 1262, in _log
    fn, lno, func = self.findCaller()
TypeError: find_caller_monkeypatch() takes exactly 1 argument (0 given)

Удаление self в качестве аргумента для find_caller_multipatch исправляет ошибку, но я запутался: почему find_caller_monkeypatch не получает self в качестве аргумента, когда он вызывается как self.findCaller()? Получают ли методы self в качестве параметра только в том случае, если они определены внутри класса?

Следующий фрагмент представляет собой меньший пример той же проблемы:

In [7]: class Foo(object):
   ...:     def say_hi(self):
   ...:         print "Hello World"
   ...:         

In [8]: def say_bye_self(self): print "Goodbye world"

In [9]: def say_bye(): print "Goodbye world"

In [10]: foo = Foo()

In [11]: foo.say_hi()
Hello World

In [12]: foo.say_hi = say_bye_self

In [13]: foo.say_hi()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-13-10baea358e0b> in <module>()
----> 1 foo.say_hi()

TypeError: say_bye_self() takes exactly 1 argument (0 given)

In [14]: foo.say_hi = say_bye

In [15]: foo.say_hi()
Goodbye world

Что тут происходит?


person Patrick Collins    schedule 07.07.2014    source источник


Ответы (1)


Вы можете установить Monkeypatch на уроке

Foo.say_hi = say_bye_self
foo = Foo()
foo.say_hi()

Или вы можете Monkeypatch экземпляр

import types
foo.say_hi = types.MethodType(say_bye_self, foo)
person bugs    schedule 07.07.2014
comment
Интересный. Но почему функция monkeypatched не получает self в качестве параметра? Я думал, что object.function() всегда передает object в качестве аргумента function. - person Patrick Collins; 07.07.2014