1

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

これに対処する方法は?

4

3 に答える 3

1
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():
    ....
于 2010-05-26T23:52:04.067 に答える
0

属性名が で始まらない場合を処理するのを忘れました'oposite_'

于 2010-05-26T23:46:15.280 に答える
0

エラーは"TypeError: <lambda>() takes at least 1 positional argument (0 given) "

lambdaこれは、メタクラスの魔法とは関係ありません。関数に引数を渡さないためです。

これを行う場合:

p.oposite_yep

関数である__getattr__の結果を返す を呼び出します。opposite()lambda

ラムダ関数が返され、オンザフライで作成され、インスタンスにバインドされることはありません。最初の引数として 'self' を受け取りません。これは、その場で返される単なる無名関数です。

したがって、これを行うと:

p.oposite_yep()

基本的に、エラーの原因となる引数なしでラムダを呼び出します。

于 2011-12-22T10:29:16.527 に答える