1

私は現在このコードを持っています:

class Generator(object):
    def __getattr__(self, name):    
        def f(self):
            return ("Result of"+name, self)
        f.__name__ = name
        return f

    def foo(self):
        pass

g = Generator()
print g.foo
print Generator.foo
print g.bar
print Generator.bar

これは次のようになります。

<bound method Generator.foo of <__main__.Generator object at 0x00B62D30>>
<unbound method Generator.foo>
<function bar at 0x00A9DE70>
AttributeError: type object 'Generator' has no attribute 'bar'

それを与えるために私は何をしなければなりませんか:

<bound method Generator.foo of <__main__.Generator object at 0x00B62D30>>
<unbound method Generator.foo>
<bound method Generator.bar of <__main__.Generator object at 0x00B62D30>>
<unbound method Generator.bar>
4

4 に答える 4

2

__getattr__()インスタンスでのみ機能します。必要な動作を実現するには、メタクラスの関数をオンにする必要がありGeneratorます。

于 2012-11-02T11:24:20.810 に答える
2

2つの問題があります。

  1. 動的関数はインスタンス g(クラスではなくGenerator)にのみ設定するため、Generator.bar定義されていません。
  2. でラップしないMethodTypeので、メソッドの代わりに関数を取得します。

g.foo1の場合、電話をかける前に常に電話をかけるGenerator.foo場合は、行を追加するだけです。

setattr(self.__class__, name, f)

内部__getattr__、クラスのメソッドとして名前をバインドします。それ以外の場合は__getattr__型オブジェクトにカスタムが必要になります。つまり、カスタムクラスのインスタンスにする必要があります。つまり、独自のメタクラスを作成する必要があります。


2については、@thg435の回答を参照してください。Python 2には下位互換性があるため、これは厄介であり、Py3kではかなり必要になっていることに注意してください。これで、基本的に機能するようになります。の自動注入によるものですself

于 2012-11-02T11:33:08.987 に答える
2

__getattr__これは、クラス定義からメタクラス自体に関数を追加するメタクラスです。これにより、関数を複数の場所で定義したり、事前に定義してメタクラスとクラスに個別に追加した個別のグローバル関数として定義したりする必要がなくなります。

class Meta(type):

    def __new__(mcls, name, bases, dikt):
        fgetattr = dikt.get('__getattr__')
        if fgetattr is not None:
            setattr(mcls, '__getattr__', fgetattr)
        return super(Meta, mcls).__new__(mcls, name, bases, dikt)

class Generator(object):
    __metaclass__ = Meta

    def __getattr__(obj, name):

        def f(self):
            return "Result of %s for %r" % (name, self)
        f.__name__ = name

        if isinstance(obj, type):
            setattr(obj, name, f)
        else:
            setattr(type(obj), name, f)
        return getattr(obj, name)

動的関数の記述子メソッドを介してメソッドを直接作成するよりも、関数をクラスdictに格納し、適切なバウンド/アンバウンドメソッドを返すことに__get__依存する方が良いと思います。getattr後続の属性アクセスでは、クラスの関数が使用されます。__getattr__クラスとインスタンスの両方に同じ関数が使用さisinstanceれるため、動的関数がインスタンスではなくクラスに格納されることを確認するためのチェックが必要です。

Python 3では、バインドされていないメソッドが言語から削除されたため、クラスの属性として関数を取得すると、関数が返されるだけです。また、メタクラスの構文がクラス定義行のキーワード引数に変更されました。

テスト:

>>> g = Generator()
>>> g.foo
<bound method Generator.foo of <__main__.Generator object at 0xb7248c2c>>
>>> Generator.foo
<unbound method Generator.foo>
>>> g.bar
<bound method Generator.bar of <__main__.Generator object at 0xb7248c2c>>
>>> Generator.bar
<unbound method Generator.bar>
>>> g.foo()
'Result of foo for <__main__.Generator object at 0xb7248c2c>'
>>> Generator.foo(g)
'Result of foo for <__main__.Generator object at 0xb7248c2c>'
>>> 'foo' in vars(Generator), 'bar' in vars(Generator)
(True, True)
于 2012-11-03T01:26:56.233 に答える
1

最初のケース(g.bar)の場合は、に置き換えreturn fますreturn MethodType(f, self)

于 2012-11-02T11:28:30.670 に答える