【问题标题】:self parameter and metaprogramming自参数和元编程
【发布时间】:2011-06-21 17:49:47
【问题描述】:

好吧,代码说话更多(我已经硬编码了一些东西,以隔离问题并使问题更短):

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。但我认为我需要用类来做这件事,因为我需要存储一些额外的信息(比如元数据)(这是我真正问题的简化版本)。有可能吗?如果有,怎么做?很抱歉没有在一开始就说明这一点。

【问题讨论】:

    标签: python metaprogramming


    【解决方案1】:

    使用函数包装器,而不是第一类。关闭将负责其余的工作:

    >>> 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
    >>>
    

    【讨论】:

    • 封口不是唯一的成分。您只会得到self,因为该类将wrapper 识别为方法并为其生成实例方法描述符。
    • 不错!暂时+1。请你解释一下这是如何工作的。我的意思是 - 包装器..我见过这样的包装器,但它们都返回帮助功能,在这种情况下 - _wrapped_meth。在这里,函数返回它的参数 - meth。何时以及如何调用/使用 _wrapped_meth
    • @delnan - 真的吗?我可以在课堂上做到这一点吗?如何?因为我需要在包装器中存储一些额外的信息——一些其他成员(元数据)等。
    • @Kiril:当然可以,如果您不介意进入描述符 - 请参阅其他答案。但是请注意,您还可以通过闭包获得额外的状态(只需将局部变量添加到 wrapper 并在 _wrapped_meth 中使用它们) - 只有当您需要其他方法时它才会变得不切实际。
    • @Kiril Kirov - 哎呀,return meth 应该是 return _wrapped_meth
    【解决方案2】:

    wrapper 设为descriptor,以便您知道被戳的具体实例。

    【讨论】:

    • 你能给我一些例子吗?我没明白,我遗漏了一些东西..(在 C++ 中没有类似的东西,对吧?)
    • 描述符只是一个类,当调用描述符的__get__()__set__() 方法时,Python 会传递有关该类和实例绑定到的额外信息。
    • 嗯,我明白了。我认为这对我有用。但是,如何使用参数调用函数。 __get__ 需要 3 个参数 - self, obj, objtype。在__init__ 我可以将函数存储为成员,但是参数呢?另外,在__get__ 我不能返回self.func( obj ) 吗? (self.func 是存储的参数,obj 是调用对象;当我返回 self.func 时,这确实返回函数,但如果返回 self.func( obj ) None :?我需要这个,看起来,第一个参数( self )应该显式传递?否则,我会因为更少的参数而出错)非常感谢!
    • 返回一个适当设置类属性的函数。
    • 我在看到你回答之前编辑了我的评论。不管怎样,我明白你的意思,我会努力的。
    【解决方案3】:

    您可以将 wrapper 类设为非数据描述符,如 Raymond Hettinger 出色的 How-To Guide for DescriptorsFunctions and Methods 部分所述——在这种情况下,这很容易,因为它只是意味着给类一个 @ 987654324@ 方法创建并返回所需的包装方法。

    这就是我的意思:

    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
    

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

    【讨论】:

    • +1 - 这正是我所做的,结合其他两个答案 (=
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-21
    • 1970-01-01
    • 2012-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-22
    相关资源
    最近更新 更多