自参数和元编程

发布于 2024-11-16 15:22:51 字数 1054 浏览 2 评论 0 原文

好吧,代码更能说明问题(我对一些东西进行了硬编码,以隔离问题并使问题更短):

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。但我认为我需要用类来做到这一点,因为我需要存储一些附加信息(如元数据)(这是我真正问题的简化版本)。这可能吗?如果可能的话,如何实现?很抱歉一开始没有指定这一点。

Well, code speaks more (I have hard-coded some things, to isolate the problem and make the question shorter):

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

I want the second print to show 1, instead of 0. In other words, is it possible, and if so - how, to pass the "real self" to my wrapper?

Note: I know why this prints 0 and I know what is the problem here ( wrapper's self is passed, instead of the object, that calls f), but I don't know how to solve it.

Any ideas?


EDIT - thanks all for the answers, +1 from me. But I think I need to do this with class, as I need to store some additional info (like metadata) (this is simplified version of my real problem). Is it possible and how, if so? Sorry for not specifying this at the very beginning.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

戈亓 2024-11-23 15:22:51

使用函数包装器,而不是一类。关闭将处理剩下的事情:

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

Use function wrapper, instead of class one. Closure will take care of the rest:

>>> 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
>>>
人事已非 2024-11-23 15:22:51

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

Make wrapper a descriptor so that you know the specific instance being poked.

你没皮卡萌 2024-11-23 15:22:51

您可以使您的 wrapper 类成为非数据描述符,如 函数和方法 部分rel="nofollow">描述符操作指南——在这种情况下非常简单,因为它只意味着给类一个__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

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

You can make your wrapper class a non-data descriptor, as described in the Functions and Methods section of Raymond Hettinger's excellent How-To Guide for Descriptors -- which in this case is pretty easy since it just means giving the class a __get__() method which creates and returns the wrapped method desired.

Here's what I mean:

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

Using a class means you can easily add other members and/or metadata as necessary.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文