Python 从外部包包装所有类方法

Python 从外部包包装所有类方法,python,python-2.7,oop,Python,Python 2.7,Oop,我一直在寻找一种方法来实现一个类包装器,它可以为任何给定的类工作很多小时。我所看到的所有解决方案要么需要访问类定义(即元类解决方案),要么完全忽略装饰类/实例方法(即setattr解决方案)的@staticmethod/@classmethod装饰器。例如,@staticmethod decorator被忽略,self仍然作为第一个参数传递给该函数 在Python2.7中如何实现这一点 例如,以下外来类:来自flask_sqlalchemy。最终的结果是,我能够在执行请求的函数调用之前调用另一个

我一直在寻找一种方法来实现一个类包装器,它可以为任何给定的类工作很多小时。我所看到的所有解决方案要么需要访问类定义(即元类解决方案),要么完全忽略装饰类/实例方法(即setattr解决方案)的@staticmethod/@classmethod装饰器。例如,@staticmethod decorator被忽略,self仍然作为第一个参数传递给该函数

在Python2.7中如何实现这一点

例如,以下外来类:来自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

我尝试过调试,但要遵循许多内部调用是相当复杂的。

我不是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
>>> 


这与您的想法类似吗?

我不是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
>>> 


这与您的想法类似吗?

请向我们展示具有所需结果的示例类。Edited请向我们展示具有所需结果的示例类。@KlausD。editedYou理解我想要实现的目标,但是这个解决方案就是前面提到的setattr解决方案@staticmethod/@classmethod修饰符和更多Python内置修饰符被忽略。尝试用@staticmethod包装myop,您将看到。您可以使用inspect模块确定静态方法inspect.isfunctionfn和方法inspect.ismethodfn,但我不确定如何识别类方法。您需要对如何为每个案例定义新包装进行分支。您了解我想要实现的目标,但这个解决方案就是前面提到的setattr解决方案@staticmethod/@classmethod修饰符和更多Python内置修饰符被忽略。尝试用@staticmethod包装myop,您将看到。您可以使用inspect模块确定静态方法inspect.isfunctionfn和方法inspect.ismethodfn,但我不确定如何识别类方法。您需要对如何为每个案例定义新包装进行分支。