Оборачивание всех методов класса из стороннего пакета - PullRequest
0 голосов
/ 27 сентября 2018

Я пытался найти способ реализовать оболочку класса, которая работает для любого данного класса в течение многих часов.Все решения, которые я видел, требуют либо доступа к определению класса (решение Meta Class), либо полностью игнорируют @staticmethod / @classmethod декораторы, которые украшают метод класса / экземпляра (решение setattr. Например, декоратор @staticmethodигнорируется, и self все еще передается этой функции в качестве первого аргумента.

Как это можно сделать в Python 2.7?

Например, следующий иностранный класс: SQLAlchemy от flask_sqlalchemy. Конечным результатом будет то, что я смогу вызвать другую функцию перед выполнением запрошенного вызова функции.

Это моя неудачная попытка:

class WithWrapping(object):
    def __init__(self, other_cls, *args, **kwargs):
        self.other = other_cls(*args, **kwargs)
        self.other_cls = other_cls

    def __getattr__(self, attr):
        other_attr = self.other.__getattribute__(attr)
        if callable(other_attr):
            other_attr = getattr(self.other_cls, attr, None)
            if not other_attr:
                other_attr = getattr(self.other, attr, None)

        def wrapper(*args, **kwargs):
            # Do something here prior to function call
            r = other_attr(*args, **kwargs)
            if r == self.other:
                return self
            return r

        return wrapper
    else:
        return other_attr

Этоне будет работать, если вы запустите следующее:

from flask_sqlalchemy import SQLAlchemy
db = WithWrapping(SQLAlchemy)
class Foo(db.TypeDecorator):
    pass

То, что вы получите:

TypeError                                 Traceback (most recent call last)
<ipython-input-4-9813b186f710> in <module>()
      1 from flask_sqlalchemy import SQLAlchemy
      2 db = WithWrapping(SQLAlchemy)
----> 3 class Foo(db.TypeDecorator):
      4     pass

TypeError: Error when calling the metaclass bases
    function() argument 1 must be code, not str

Что я пытался отладить, но довольно сложно следить за многими внутренними вызовами там.

1 Ответ

0 голосов
/ 27 сентября 2018

Я не на 100% уверен в том, чего вы хотите достичь, но вы можете просмотреть компоненты объекта или класса и обернуть их собственным декоратором, используя такие вещи, как dir (), callable () и setattr ().



import functools

class A (object) :
    def __init__( self ):
        pass
    def myop( self, a, b ):
        return a + b

def mydec( fn ):
    @functools.wraps(fn)
    def wrapper( obj, *args, **kwargs ):
        print( "called" )
        return fn( obj, *args, **kwargs )
    return wrapper


for name in dir( A ):
    if not name.startswith( "_" ) : # probably want to think carefully about this!
        attr = getattr( A, name )
        if callable(attr):
            setattr( A, name, mydec( attr ) )

приводит к



>>> a = A()
>>> a.myop( 1, 3 )
called
4
>>> 


Это похоже на то, что вы имели в виду?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...