web-dev-qa-db-ja.com

クラスオブジェクトのカスタム文字列表現を作成するには?

このクラスを検討してください:

class foo(object):
    pass

デフォルトの文字列表現は次のようになります。

>>> str(foo)
"<class '__main__.foo'>"

これをカスタム文字列に表示するにはどうすればよいですか?

169
Björn Pollex

クラスのメタクラスに__str__()または__repr__()を実装します。

class MC(type):
  def __repr__(self):
    return 'Wahaha!'

class C(object):
  __metaclass__ = MC

print C

読みやすい文字列化を意味する場合は__str__を使用し、明確な表現には__repr__を使用します。

232
class foo(object):
    def __str__(self):
        return "representation"
    def __unicode__(self):
        return u"representation"
21
Andrey Gubarev

__repr__または__str__のいずれかを選択する必要がある場合は、デフォルトの実装として__str__が定義されていないときに__repr__を呼び出します。

カスタムVector3の例:

class Vector3(object):
    def __init__(self, args):
        self.x = args[0]
        self.y = args[1]
        self.z = args[2]

    def __repr__(self):
        return "Vector3([{0},{1},{2}])".format(self.x, self.y, self.z)

    def __str__(self):
        return "x: {0}, y: {1}, z: {2}".format(self.x, self.y, self.z)

この例では、reprは再び直接使用/実行できる文字列を返しますが、strはデバッグ出力としてより便利です。

v = Vector3([1,2,3])
print repr(v)    #Vector3([1,2,3])
print str(v)     #Vector(x:1, y:2, z:3)
9
user1767754

Ignacio Vazquez-Abramsの承認済みの答え はまったく正しい。ただし、Python 2世代のものです。現在のPython 3の更新は次のようになります。

class MC(type):
  def __repr__(self):
    return 'Wahaha!'

class C(object, metaclass=MC):
    pass

print(C)

Python 2とPython 3の両方で実行されるコードが必要な場合は、 six モジュールでカバーできます。

from __future__ import print_function
from six import with_metaclass

class MC(type):
  def __repr__(self):
    return 'Wahaha!'

class C(with_metaclass(MC)):
    pass

print(C)

最後に、カスタムの静的リポジトリを持ちたいクラスが1つある場合、上記のクラスベースのアプローチは非常に効果的です。しかし、複数ある場合は、それぞれMCに似たメタクラスを生成する必要があり、面倒になります。その場合、メタプログラミングをさらに一歩進めてメタクラスファクトリを作成すると、少しわかりやすくなります。

from __future__ import print_function
from six import with_metaclass

def custom_class_repr(name):
    """
    Factory that returns custom metaclass with a class ``__repr__`` that
    returns ``name``.
    """
    return type('whatever', (type,), {'__repr__': lambda self: name})

class C(with_metaclass(custom_class_repr('Wahaha!'))): pass

class D(with_metaclass(custom_class_repr('Booyah!'))): pass

class E(with_metaclass(custom_class_repr('Gotcha!'))): pass

print(C, D, E)

プリント:

Wahaha! Booyah! Gotcha!

メタプログラミングは一般に日常的に必要なものではありませんが、必要なときにすぐに使用できます。

3
Jonathan Eunice

すべての素晴らしい答えに加えて、装飾付きの私のバージョン:

from __future__ import print_function
import six

def classrep(rep):
    def decorate(cls):
        class RepMetaclass(type):
            def __repr__(self):
                return rep

        class Decorated(six.with_metaclass(RepMetaclass, cls)):
            pass

        return Decorated
    return decorate


@classrep("Wahaha!")
class C(object):
    pass

print(C)

標準出力:

Wahaha!

欠点:

  1. スーパークラスなしではCを宣言できません(class C:はありません)
  2. Cインスタンスは奇妙な派生のインスタンスであるため、インスタンスにも__repr__を追加することをお勧めします。
0
Aviv Goll