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