Простой объект регистрации

У меня есть модуль 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.

Если есть ошибки или они написаны не на питонском языке, укажите на них.

Кроме того, Я подозреваю, что это можно легко сделать с помощью decorators, но, к сожалению, я не могу найти подходящий способ и понятия не имею, что может случиться, если ModuleClass уже имеет некоторые декораторы методов.

Не могли бы вы мне тоже помочь?


person Yippie-Ki-Yay    schedule 15.11.2011    source источник
comment
При написании Python забудьте о Java. Семантика этих двух вещей даже не близка друг к другу.   -  person Cat Plus Plus    schedule 16.11.2011
comment
@CatPlusPlus Хорошо, но я думаю, тогда должен быть хороший способ решить эту проблему в python.   -  person Yippie-Ki-Yay    schedule 16.11.2011
comment
Ошибка Python: super - это не объект, а метод. Чтобы вызвать родительский конструктор, вам нужно вызвать super () .__ init __ (), а для вызова родительского метода вы должны вызвать super (). Method () (я полагаю, вы используете python 3 ...)   -  person gecco    schedule 16.11.2011


Ответы (3)


Если вам действительно нужна оболочка, просто напишите ее, без подклассов и промежуточных классов.

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()
person Cat Plus Plus    schedule 15.11.2011
comment
Итак, из-за семантики python любой экземпляр этого класса можно передать функции, где ожидается ModuleClass? - person Yippie-Ki-Yay; 16.11.2011
comment
Есть ли у python случайно функции с контрактами типа the instance of the passed class should be a 'ModuleClass'? Или это ява внутри меня говорит? - person Yippie-Ki-Yay; 16.11.2011
comment
@ Yippie-Kai-Yay: Python использует утиную типизацию, интерфейсы являются неявными (если у объекта есть метод X, его можно использовать везде, где требуется метод X). Вы можете использовать isinstance для подтверждения типа, но в общем коде этого лучше избегать. - person Cat Plus Plus; 16.11.2011
comment
Большое Вам спасибо. Правильно ли я понимаю, что этот способ создания прокси не нарушает существующее оформление method1, method2, если оно присутствует? И будет ли это работать все время, или есть какие-то угловые случаи, кроме isinstance, когда это может не сработать? - person Yippie-Ki-Yay; 16.11.2011

Как насчет прямого подкласса 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)

(Я добавил код, чтобы показать базовую настройку для ведения журнала способом Python) .

person unutbu    schedule 15.11.2011
comment
class LoggingModuleClass, а не def. - person Cat Plus Plus; 16.11.2011
comment
Да, это то, о чем говорит Effective Java. Иногда, если вы вызываете method2, реализация которого неявно вызывает method1, вы получаете нежелательные сообщения в своем журнале (ну, по крайней мере, в моем случае они нежелательны). Это цель класса пересылки. Тем не менее, спасибо, и, возможно, если вы знаете решение с декораторами, вы тоже можете мне помочь. - person Yippie-Ki-Yay; 16.11.2011
comment
@unutbu Да, я подозреваю, что пакет logging, вероятно, подойдет. Но (просто из любопытства), например, если я хочу добавить бенчмаркинг так же, как описано в вопросе - возможно ли это с помощью декораторов? - person Yippie-Ki-Yay; 16.11.2011

Если вы ищете решение для декоратора, вам следует взглянуть на ответ этого сообщения: Декоратор Python заставляет функцию забыть, что она принадлежит классу

Вы указали, что хотите избежать «нежелательных сообщений» (в случае, если method1 вызывает method2), тогда я предлагаю вам выбрать решение, предоставляемое Cat Plus Plus, иначе я бы выбрал операторов.

person gecco    schedule 15.11.2011