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

时间:2018-09-27 17:46:03

标签: python python-2.7 oop

我一直在尝试找到一种方法来实现对任何给定类都可用很多小时的类包装器。我见过的所有解决方案都需要访问类定义(Meta Class解决方案),或者完全忽略装饰类/实例方法的@staticmethod / @classmethod装饰器(setattr解决方案例如@staticmethod装饰器将被忽略,而self仍作为第一个参数传递给该函数)。

如何在Python 2.7中完成?

例如以下外部类:flask_sqlalchemy中的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 :(得分:-1)

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


这与您的想法相似吗?