【问题标题】:Simple logging object简单的日志记录对象
【发布时间】:2011-12-29 22:18:09
【问题描述】:

我有一些 python 模块,它有一个 ModuleClass 类,我无法修改该类。

现在,我希望能够代理方法调用并添加某些日志记录功能。我认为这应该通过转发对象和相应的代理 (following Effective Java, Item 16) 来完成。

我想出的python 伪代码如下。

(抱歉,我的 python 真的很糟糕,如果您能在此处指出错误,我将不胜感激。

# This is what I've got in my module and this code cannot be changed.
class ModuleClass(object):
    def method1(self):
        # Some implementation
        pass()
    def method2(self):
        # Some implementation
        pass()

# Simple forwarding proxy to avoid the situation described in Effective Java, I16

# However, in Java this class would usually be extending the interface, not
# inheriting 'ModuleClass' (I'm confused and don't know how to do the same
# in python).

class ForwardingModuleClass(ModuleClass):
    # 'proxifiedObject' is 
    def __init__(self, proxifiedObject):
        self.proxifiedObject = proxifiedObject

    # Overriding the first method
    def method1(self):
        return self.proxifiedObject.method1()

    # Same for method2...

class LoggingModuleClass(ForwardingModuleClass):
    # 'classThatActuallyDoesStuff' should be an instance of 'ModuleClass'.
    def __init__(self, classThatActuallyDoesStuff):
        # Sorry for my bad knowledge of python syntax, but
        # I assume I can initialize the superclass here using
        # the supplied 'ModuleClass' instance.
        super(classThatActuallyDoesStuff)

    # Overriding the first method.
    def method1(self):
        print("Yay! This 'method1' really logs something!")
        return super.method1()

    # Overriding the second method.
    def method2(self):
        print("Yay!!!! This 'method2' also does something cool!")
        return super.method2()

现在,我想,如果写得正确,这将起作用,并且我将拥有我最初的 ModuleClass 的日志记录代理。

如果有错误或者不是pythonish,请指出。

另外,我怀疑这可以使用decorators 轻松完成, 但不幸的是,我想不出合适的方法,我不知道如果ModuleClass 已经有了会发生什么一些方法装饰器。

你也可以帮我吗?

【问题讨论】:

  • 在编写 Python 时忘记 Java。两者的语义甚至并不接近。
  • @CatPlusPlus 好的,但我想python 应该有一个很好的方法来解决这个问题。
  • Python 错误:super 不是对象而是方法。要调用父母构造函数,您必须调用 super().__init__() 并调用 parent 方法,您应该调用 super().method() (我想您使用的是 python 3...)

标签: python logging decorator proxy-classes


【解决方案1】:

如果你真的想要一个包装器,那么只需编写它,没有子类和中间类。

class LoggingFoo(object):
    def __init__(self, *args, **kwargs):
        self.obj = Foo(*args, **kwargs)

    def method1(self):
        # ...
        return self.obj.method1()

    def method2(self):
        # ...
        return self.obj.method2()

【讨论】:

  • 那么,由于python语义,这个类的任何实例都可以传递给预期ModuleClass的函数?
  • python 有没有像the instance of the passed class should be a 'ModuleClass' 这样的合约的函数?还是这个 java 在我心里说话?
  • @Yippie-Kai-Yay:Python 使用鸭子类型,接口是隐式的(如果对象有方法 X,它可以在需要方法 X 的任何地方使用)。你可以使用isinstance 来断言类型,但泛型代码应该避免它。
  • 非常感谢。我是否正确意识到这种制作代理的方式不会破坏method1method2 的现有装饰(如果存在)?这会一直有效吗,或者除了isinstance 之外还有一些极端情况可能会失败?
【解决方案2】:

直接继承 ModuleClass 怎么样:

import logging

logger=logging.getLogger(__name__)

class LoggingModuleClass(ModuleClass):
    def method1(self):
        logger.info("Yay! This 'method1' really logs something!")
        return super(LoggingModuleClass,self).method1()
    def method2(self):
        logger.info("Yay! This 'method2' also does something cool!")
        return super(LoggingModuleClass,self).method2()

logging.basicConfig(level=logging.DEBUG)

(我添加了代码以显示logging Python 方式的基本设置)。

【讨论】:

  • class LoggingModuleClass,而不是def
  • 是的,这就是Effective Java 所说的。有时,如果您调用method2,该实现隐式调用method1,您会在日志中收到不需要的消息(至少在我的情况下,它们是不需要的)。这就是转发类的目的。 不过,谢谢,如果你知道装饰器的解决方案,你也可以在这里帮助我。
  • @unutbu 是的,我怀疑logging 包可能会做得很好。但是(只是好奇),例如,如果我想以与问题中所述相同的方式添加基准测试 - 是否可以使用装饰器?
【解决方案3】:

如果您正在寻找装饰器解决方案,那么您应该看看这篇文章的答案:Python decorator makes function forget that it belongs to a class

您表示要避免“不需要的消息”(如果method1调用method2),那么我建议您选择Cat Plus Plus提供的解决方案,否则我会选择运营商。

【讨论】:

    猜你喜欢
    • 2016-04-22
    • 2019-09-29
    • 1970-01-01
    • 2011-01-29
    • 2018-06-13
    • 1970-01-01
    • 2012-03-27
    • 2019-10-12
    • 2016-02-23
    相关资源
    最近更新 更多