嗯,代码说得更多(我已经对一些东西进行了硬编码,以隔离问题并缩短问题):
class wrapper:
def __init__( self, func ):
self.func = func
def __call__( self, *args ):
print( "okay, arg = ", args[0] )
self.func( self, args )
class M( type ):
def __new__( klass, name, bases, _dict ):
_dict[ "f" ] = wrapper( _dict[ "f" ] )
return type.__new__( klass, name, bases, _dict )
class AM( metaclass = M ):
def __init__( self ):
self.a = 0
def f( self, a ):
self.a = a
am = AM()
print( am.a ) # prints 0, expected
am.f( 1 ) # prints: "okay, arg = 1"
print( am.a ) # prints 0 again, also expected
我希望第二次打印显示1
,而不是0
。换句话说,将“真实的自我”传递给我的包装器是否可能,如果是这样 - 如何?
注意:我知道为什么这会打印0
而我知道这里有什么问题(wrapper
的自我传递,而不是该对象,调用f
),但我不知道如何解决它。
有什么想法吗?
编辑 - 感谢大家的回答,+1来自我。但我认为我需要在课堂上这样做,因为我需要存储一些额外的信息(比如元数据)(这是我真实问题的简化版)。是否有可能以及如果是这样的话?很抱歉没有在一开始就指明这一点。
答案 0 :(得分:6)
使用函数包装器而不是第一类。关闭将负责其余的事情:
>>> def wrapper(meth):
... def _wrapped_meth(self, *args):
... print('okay, arg = ', args)
... meth(self, *args)
... return _wrapped_meth
...
>>> class M(type):
... def __new__(klass, name, bases, dct):
... dct['f'] = wrapper(dct['f'])
... return type.__new__(klass, name, bases, dct)
...
>>> class AM(metaclass=M):
... def __init__(self):
... self.a = 0
... def f(self, a):
... self.a = a
...
>>> am = AM()
>>> print(am.a)
0
>>> am.f(1)
okay, arg = (1,)
>>> print(am.a)
1
>>>
答案 1 :(得分:3)
使wrapper
成为descriptor,以便您知道正在调查的具体实例。
答案 2 :(得分:1)
您可以将wrapper
类设为非数据描述符,如Raymond Hettinger的优秀Functions and Methods的How-To Guide for Descriptors部分所述 - 在这种情况下很简单,因为它只是表示为类提供一个__get__()
方法,该方法创建并返回所需的包装方法。
这就是我的意思:
class wrapper:
def __init__( self, func ):
self.func = func
def __get__( self, instance, owner ):
def wrapped( *args ):
print( "okay, arg = ", args[0] )
return self.func( instance, *args )
return wrapped
使用类意味着您可以根据需要轻松添加其他成员和/或元数据。