我一直在尝试找到一种方法来实现对任何给定类都可用很多小时的类包装器。我见过的所有解决方案都需要访问类定义(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
我尝试过调试,但是遵循那里的许多内部调用非常复杂。
答案 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
>>>
这与您的想法相似吗?