Автопараметрия и метапрограммирование
Ну, код говорит больше (я жестко закодировал некоторые вещи, чтобы изолировать проблему и сделать вопрос короче):
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 от меня. Но я думаю, что мне нужно сделать это с классом, так как мне нужно хранить некоторую дополнительную информацию (например, метаданные) (это упрощенная версия моей настоящей проблемы). Возможно ли это и как, если да? Извините, что не указали это в самом начале.
3 ответа
Делать wrapper
дескриптор, чтобы вы знали конкретный экземпляр тыкают.
Используйте функцию-оболочку вместо одного класса. Закрытие позаботится об остальном:
>>> 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
>>>
Вы можете сделать свой wrapper
классифицировать дескриптор, не связанный с данными, как описано в разделе " Функции и методы " превосходного практического руководства по дескрипторам Рэймонда Хеттингера, что в данном случае довольно просто, так как это просто означает __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
Использование класса означает, что вы можете легко добавлять других членов и / или метаданные по мере необходимости.