在 Python 中使用 getattr 调用方法

发布于 2024-09-02 23:01:50 字数 996 浏览 1 评论 0原文

如何使用 getattr 调用方法? 我想创建一个元类,它可以调用以“oposite_”一词开头的其他类的不存在方法。该方法应该具有相同数量的参数,但返回相反的结果。

def oposite(func):
    return lambda s, *args, **kw:  not oposite(s, *args, **kw)


class Negate(type):
    def __getattr__(self, name):
        if name.startswith('oposite_'):
            return oposite(self.__getattr__(name[8:]))        
    def __init__(self,*args,**kwargs):
        self.__getattr__ = Negate.__getattr__


class P(metaclass=Negate):
    def yep(self):
        return True
    def maybe(self, sth):
        return sth

但问题是

self.__getattr__(sth) 

返回一个 NoneType 对象。

>>> p = P()
>>> p.oposite_yep()    #should be False
Traceback (most recent call last):
  File "<pyshell#115>", line 1, in <module>
    p.oposite_yep()
TypeError: <lambda>() takes at least 1 positional argument (0 given)
>>> p.oposite_maybe(False)    #should be true

这该如何处理呢?

How to call a method using getattr?
I want to create a metaclass, which can call non-existing methods of some other class that start with the word 'oposite_'. The method should have the same number of arguments, but to return the opposite result.

def oposite(func):
    return lambda s, *args, **kw:  not oposite(s, *args, **kw)


class Negate(type):
    def __getattr__(self, name):
        if name.startswith('oposite_'):
            return oposite(self.__getattr__(name[8:]))        
    def __init__(self,*args,**kwargs):
        self.__getattr__ = Negate.__getattr__


class P(metaclass=Negate):
    def yep(self):
        return True
    def maybe(self, sth):
        return sth

But the problem is that

self.__getattr__(sth) 

returns a NoneType object.

>>> p = P()
>>> p.oposite_yep()    #should be False
Traceback (most recent call last):
  File "<pyshell#115>", line 1, in <module>
    p.oposite_yep()
TypeError: <lambda>() takes at least 1 positional argument (0 given)
>>> p.oposite_maybe(False)    #should be true

How to deal with this?

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

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

发布评论

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

评论(3

她说她爱他 2024-09-09 23:01:50
class Negate(type):
    def __getattr__(self, name):
        if name.startswith('oposite_'):
            def oposite(*args,**kwargs):
                return not getattr(self,name[8:])(*args,**kwargs)
            return oposite
        else:
            raise AttributeError("%r object has no attribute %r" %
                                 (type(self).__name__, name))

    def __init__(self,*args,**kwargs):
        self.__getattr__ = Negate.__getattr__

class P(metaclass=Negate):
    def yep(self):
        return True
    def same(self,x,y):
        return x==y

p=P()
print(p.oposite_yep())
# False
print(p.oposite_same(1,2))
# True
print(p.nope())

顺便说一句,您也可以使用类装饰器而不是元类来完成此操作:

def Negater(cls):
    def __getattr__(self, name):
        if name.startswith('oposite_'):
            def oposite(*args,**kwargs):
                return not getattr(self,name[8:])(*args,**kwargs)
            return oposite
        else:
            raise AttributeError("%r object has no attribute %r" %
                                 (type(self).__name__, name))
    setattr(cls,'__getattr__',__getattr__)
    return cls

@Negater
class P():
    ....
class Negate(type):
    def __getattr__(self, name):
        if name.startswith('oposite_'):
            def oposite(*args,**kwargs):
                return not getattr(self,name[8:])(*args,**kwargs)
            return oposite
        else:
            raise AttributeError("%r object has no attribute %r" %
                                 (type(self).__name__, name))

    def __init__(self,*args,**kwargs):
        self.__getattr__ = Negate.__getattr__

class P(metaclass=Negate):
    def yep(self):
        return True
    def same(self,x,y):
        return x==y

p=P()
print(p.oposite_yep())
# False
print(p.oposite_same(1,2))
# True
print(p.nope())

By the way, you can also do this with a class decorator instead of a metaclass:

def Negater(cls):
    def __getattr__(self, name):
        if name.startswith('oposite_'):
            def oposite(*args,**kwargs):
                return not getattr(self,name[8:])(*args,**kwargs)
            return oposite
        else:
            raise AttributeError("%r object has no attribute %r" %
                                 (type(self).__name__, name))
    setattr(cls,'__getattr__',__getattr__)
    return cls

@Negater
class P():
    ....
勿挽旧人 2024-09-09 23:01:50

您忘记处理属性名称​​不'oposite_'开头的情况。

You forgot to handle the case where the attribute name doesn't start with 'oposite_'.

吐个泡泡 2024-09-09 23:01:50

错误是 “TypeError:() 至少需要 1 个位置参数(给定 0 个)

这与你的元类魔法无关,这是因为你没有将任何参数传递给lambda函数。

当你这样做时:

p.oposite_yep

它调用__getattr__,它返回 opposite() 的结果,这是一个 lambda 函数。

返回您的 lamda 函数,它是动态创建的,并且永远不会绑定到实例。它不会接收“self”作为第一个参数:它只是一个动态返回的匿名函数,

所以当你这样做时:

p.oposite_yep()

你基本上是在不带任何参数的情况下调用 lambda,这会导致错误。

The error is "TypeError: <lambda>() takes at least 1 positional argument (0 given)
"

This has nothing to do with you metaclass magic, it's because you don't pass any argument to the lambda function.

When you do this:

p.oposite_yep

It call __getattr__, which returns the result of opposite(), which is a lambda function.

Your lamda function is returned, it is created on the fly, and never bouned to the instance. It won't receive 'self' as a first argument: it's just an anonymous function returned on the fly.

So when you do this:

p.oposite_yep()

You basically call the lambda, without any argument, which cause the error.

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