web-dev-qa-db-ja.com

__repr __()のデフォルトの動作を取得するにはどうすればよいですか?

誰かがPythonでクラスを作成し、独自の__repr__()メソッドを指定しなかった場合、デフォルトのメソッドが提供されます。ただし、デフォルトの__repr__()と同じまたは類似の動作をする関数を作成するとします。ただし、クラスの実際の__repr__()がオーバーロードされた場合でも、この関数にデフォルトの__repr__()メソッドの動作を持たせる必要があります。つまり、誰かが__repr__()メソッドをオーバーロードしたかどうかに関係なく、デフォルトの__repr__()と同じ動作をする関数を記述したいとします。どうすればいいですか?

_class DemoClass:
    def __init__(self):
        self.var = 4
    def __repr__(self):
        return str(self.var)

def true_repr(x):
    # [magic happens here]
    s = "I'm not implemented yet"
    return s

obj = DemoClass()

print(obj.__repr__())

print(true_repr(obj))
_

必要な出力:

print(obj.__repr__())は_4_を出力しますが、print(true_repr(obj))は次のように出力します。
_<__main__.DemoClass object at 0x0000000009F26588>_

15

object.__repr__(obj)を使用できます。これが機能するのは、デフォルトのreprの動作がobject.__repr__で定義されているためです。

23
internet_user

他の人が指摘しているように、最良の答えはおそらくobject.__repr__を直接使用することです。しかし、大まかに次のように同じ機能を実装できます。

>>> def true_repr(x):
...     type_ = type(x)
...     module = type_.__module__
...     qualname = type_.__qualname__
...     return f"<{module}.{qualname} object at {hex(id(x))}>"
...

そう....

>>> A()
hahahahaha
>>> true_repr(A())
'<__main__.A object at 0x106549208>'
>>>
10

通常、そのために_object.__repr___を使用できますが、これは「 every アイテムのオブジェクトreprになります。したがって、次のようになります。

_>>> object.__repr__(4)
'<int object at 0xa6dd20>'
_

intobjectですが、___repr___がオーバーライドされているためです。

one の上書きレベルを上げたい場合は、super(..)を使用できます。

_>>> super(type(4), 4).__repr__()  # going up one level
'<int object at 0xa6dd20>'
_

intの場合、これも_<int object at ...>_を出力することを意味しますが、たとえばintをサブクラス化する場合は、次のようにintの___repr___を再度使用します。

_class special_int(int):

    def __repr__(self):
        return 'Special int'
_

次に、次のようになります。

_>>> s = special_int(4)
>>> super(type(s), s).__repr__()
'4'
_

ここでは、super(..)を使用して proxy オブジェクトを作成します。 Superは、オブジェクトのメソッド解決順序(MRO)をウォークし、関数をオーバーライドした最初の関数(sのスーパークラスから)を見つけようとします。単一の継承を使用する場合、それは関数をオーバーライドする最も近い親ですが、多重継承が含まれる場合、これはより注意が必要です。したがって、その親の___repr___を選択し、その関数を呼び出します。

通常、クラス(ここではtype(s))は固定クラスであり、 not super自体のタイプに依存しないため、これもsのかなり奇妙なアプリケーションです。そうしないと、そのようなsuper(..)呼び出しが複数回発生すると、無限ループが発生するためです。

しかし、通常、とにかくオーバーライドを解除することは悪い考えです。プログラマーが関数をオーバーライドする理由は、動作を変更するです。もちろん、これを尊重しないと、いくつかの便利な機能が得られる場合がありますが、多くの場合、コードコントラクトが満たされないという事実が生じます。たとえば、プログラマーが___eq___をオーバーライドする場合、別のクラスのハッシュと実際の___hash___を使用する場合、プログラマーは___eq___もオーバーライドします。

マジック関数を直接呼び出すことも、アンチパターンと見なされることが多いため、これも避けた方がよいでしょう。

9