猴子补丁 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
里面的东西,而不是调用这个函数的地方。
我通过参考 这个 很棒的答案,修复了这个问题,方法是对 EasyLogger.logger
的 findCaller
方法进行了猴子补丁,代码如下:
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)
去掉 find_caller_monkeypatch
的 self
参数后,错误就解决了,但我还是不明白:为什么在调用 self.findCaller()
时,find_caller_monkeypatch
没有接收到 self
作为参数?方法只有在类里面定义时才会接收 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
这是怎么回事呢?
1 个回答
2
你可以对这个类进行猴子补丁(Monkeypatch)
Foo.say_hi = say_bye_self
foo = Foo()
foo.say_hi()
或者你也可以对某个实例进行猴子补丁
import types
foo.say_hi = types.MethodType(say_bye_self, foo)