0

__repr__()クラスのデフォルトがあまり有益ではないことは私を悩ませます:

>>> class Opaque(object): pass
... 
>>> Opaque()
<__main__.Opaque object at 0x7f3ac50eba90>

...だから私はそれを改善する方法を考えてきました。pickle少し検討した後、プロトコルの__getnewargs__()メソッドを活用するこの抽象基本クラスを思いつきました。

from abc import abstractmethod

class Repro(object):

    """Abstract base class for objects with informative ``repr()`` behaviour."""

    @abstractmethod
    def __getnewargs__(self):
        raise NotImplementedError

    def __repr__(self):
        signature = ", ".join(repr(arg) for arg in self.__getnewargs__())
        return "%s(%s)" % (self.__class__.__name__, signature)

その使用法の簡単な例を次に示します。

class Transparent(Repro):

    """An example of a ``Repro`` subclass."""

    def __init__(self, *args):
        self.args = args

    def __getnewargs__(self):
        return self.args

...そして結果として生じるrepr()振る舞い:

>>> Transparent("an absurd signature", [1, 2, 3], str)
Transparent('an absurd signature', [1, 2, 3], <type 'str'>)
>>> 

これで、Pythonがデフォルトでこれをすぐに行わない理由の1つがわかります。すべてのクラスにメソッドを定義するように要求することは、メソッド__getnewargs__()を定義することを期待する(ただし要求しない)よりも負担が大きくなります__repr__()

私が知りたいのは、それはどれほど危険で壊れやすいのかということです。一方で、Reproインスタンスにそれ自体が含まれている場合、無限の再帰が発生することを除いて、ひどく間違っている可能性のあるものは考えられません...しかし、上記のコードを醜くするという犠牲を払って、それは解決可能です。

他に何を逃しましたか?

4

2 に答える 2

4

このようなことに興味がある場合は__init__、デコレータを使用して引数を自動的に取得してみませんか? そうすれば、手動でそれらを処理することでユーザーに負担をかける必要がなくなり、複数の引数を持つ通常のメソッド シグネチャを透過的に処理できます。これが私が思いついた簡単なバージョンです:

def deco(f):
    def newFunc(self, *args, **kwargs):
        self._args = args
        self._kwargs = kwargs
        f(self, *args, **kwargs)
    return newFunc
class AutoRepr(object):
    def __repr__(self):
        args = ', '.join(repr(arg) for arg in self._args)
        kwargs = ', '.join('{0}={1}'.format(k, repr(v)) for k, v in self._kwargs.iteritems())
        allArgs = ', '.join([args, kwargs]).strip(', ')
        return '{0}({1})'.format(self.__class__.__name__, allArgs)

これで、AutoRepr のサブクラスを通常の__init__シグネチャで定義できるようになりました。

class Thingy(AutoRepr):
    @deco
    def __init__(self, foo, bar=88):
        self.foo = foo
        self.bar = bar

そして__repr__自動的に動作します:

>>> Thingy(1, 2)
Thingy(1, 2)
>>> Thingy(10)
Thingy(10)
>>> Thingy(1, bar=2)
Thingy(1, bar=2)
>>> Thingy(bar=1, foo=2)
Thingy(foo=2, bar=1)
>>> Thingy([1, 2, 3], "Some junk")
Thingy([1, 2, 3], 'Some junk')

@decoあなたを着る__init__ことは、全体を書くよりもはるかに簡単です__getnewargs__. もしそれをしたくなければ__init__、この方法でメソッドを自動的にデコレートするメタクラスを書くことができます。

于 2012-11-18T21:40:59.687 に答える