自我参数和元编程

时间:2011-06-21 17:49:48

标签: python metaprogramming

嗯,代码说得更多(我已经对一些东西进行了硬编码,以隔离问题并缩短问题):

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 个答案:

答案 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 MethodsHow-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

使用类意味着您可以根据需要轻松添加其他成员和/或元数据。