サーチ…


備考

両方のメソッドの実装に関する注意

両方の方法が実装されている場合は、それが持っている、やや一般的です__str__人に優しい表現(例えば、「スペースのエース」)を返し、メソッド__repr__返すevalやさしい表現を。

実際、 repr() Pythonドキュメントはこれを正確にメモしています:

多くの型では、この関数はeval()に渡されるときに同じ値を持つオブジェクトを生成する文字列を返そうとします。さもなければ、その表現はオブジェクトの型の名前を含む山括弧で囲まれた文字列です多くの場合、オブジェクトの名前とアドレスを含む追加情報があります。

つまり、 __str__実装して__str__ように「Ace of Spaces」のようなものを返すことができますが、代わりに__repr__実装してCard('Spades', 1)

この文字列は、ある程度「往復」でevalに直接渡すことができます:

object -> string -> object

このようなメソッドの実装例は次のとおりです。

def __repr__(self):
    return "Card(%s, %d)" % (self.suit, self.pips)

ノート

[1]この出力は実装固有のものです。表示される文字列はcpythonのものです。

[2]あなたはすでにこのstr() / repr()の結果を分かっていて、分かっていないかもしれません。バックスラッシュなどの特殊文字を含む文字列がstr()を介して文字列に変換されると、バックスラッシュはそのまま表示されstr()一度表示されます)。それらがrepr()を介して文字列に変換されると(たとえば、表示されるリストの要素として)、バックスラッシュはエスケープされて2回表示されます。

動機

だから、ちょうどあなたの最初のクラスをPythonで作成しました。これはトランプカードをカプセル化したきちんとした小さなクラスです:

class Card:
    def __init__(self, suit, pips):
        self.suit = suit
        self.pips = pips

コードのどこかで、このクラスのいくつかのインスタンスを作成します。

ace_of_spades = Card('Spades', 1)
four_of_clubs = Card('Clubs',  4)
six_of_hearts = Card('Hearts', 6)

あなたは "手"を表すためにカードのリストを作成しました。

my_hand = [ace_of_spades, four_of_clubs, six_of_hearts]

今、デバッグ中に、あなたの手の様子を見たいので、自然に来て何をするのかをします:

print(my_hand)

しかし、あなたが戻ってくるものは、ぎこちない言葉です。

[<__main__.Card instance at 0x0000000002533788>, 
 <__main__.Card instance at 0x00000000025B95C8>, 
 <__main__.Card instance at 0x00000000025FF508>]

混乱していると、1枚のカードだけを印刷しようとします:

print(ace_of_spades)

そしてもう一度、あなたはこの奇妙な結果を得ます:

<__main__.Card instance at 0x0000000002533788>

何も怖くない。これを直すつもりです。

まず、ここで何が起こっているのかを理解することが重要です。あなたがprint(ace_of_spades)を書いたとき、Pythonにあなたのコードがace_of_spades呼び出しているCardインスタンスに関する情報を出力したかったとace_of_spades 。そして、公正であるために、それはしました。

その出力は、オブジェクトのtypeとオブジェクトのidの2つの重要なビットで構成されます。 2番目の部分だけ(16進数)は、 print呼び出し時にオブジェクトを一意に識別するのに十分です。[1]

本当に続いたのは、Pythonにオブジェクトの本質を "言葉で伝え"て、それをあなたに表示するように頼んだことでした。同じマシンのより明示的なバージョンは、次のようなものです。

string_of_card = str(ace_of_spades)
print(string_of_card)

最初の行では、 Cardインスタンスを文字列に変換し、次にインスタンスを表示します。

問題

あなたが遭遇している問題は、あなたがPythonにCard作成するためのCardクラスについて知っておく必要があるすべてのことについて、あなたがCardインスタンスを文字列に変換する方法を教えていないという事実のために起こります。

そしてそれがわからないので、(暗黙のうちに)あなたがstr(ace_of_spades)書いたとき、それはあなたが見たもの、つまりCardインスタンスの一般的な表現を与えました。

解決策(その1)

しかし、カスタムクラスのインスタンスをどのように文字列に変換するかをPythonに伝えることができます。そして、私たちがこれを行う方法は、 __str__ "dunder"(ダブルアンダースコアの場合)または "magic"メソッドの場合です。

クラスインスタンスから文字列を作成するようにPythonに指示するたびに、クラスで__str__メソッドが検索され、呼び出されます。

私たちのCardクラスの次のアップデートバージョンを考えてみましょう。

class Card:
    def __init__(self, suit, pips):
        self.suit = suit
        self.pips = pips

    def __str__(self):
        special_names = {1:'Ace', 11:'Jack', 12:'Queen', 13:'King'}

        card_name = special_names.get(self.pips, str(self.pips))

        return "%s of %s" % (card_name, self.suit)

ここでは、 __str__メソッドをCardクラスに定義しました。これは、簡単な辞書検索の後、フォーマットされた文字列を返します

(文字列を返すことの重要性を強調するために、 "返品"はここでは太字で示していますが、単純に印刷するのではなく、印刷すると思われるかもしれませんが、 str(ace_of_spades) 、あなたのメインプログラムでprint関数の呼び出しをしなくても、 __str__が文字列を返すことを確認して__str__

__str__メソッドはメソッドなので、最初の引数はselfあり、 __str__引数を受け入れることも渡すべきでもありません。

カードをよりユーザーフレンドリーな方法で表示するという問題に戻り、再び実行すると:

ace_of_spades = Card('Spades', 1)
print(ace_of_spades)

私たちの出力がはるかに優れていることがわかります:

Ace of Spades

偉大な、私たちは完了ですよね?

私たちの拠点をカバーするだけで、遭遇した最初の問題を解決したことをもう一度確認して、 Cardインスタンスのリストであるhand印刷してみましょう。

そこで次のコードを再確認します:

my_hand = [ace_of_spades, four_of_clubs, six_of_hearts]
print(my_hand)

そして、私たちの驚くべきことに、それらの面白い16進コードをもう一度得ます:

[<__main__.Card instance at 0x00000000026F95C8>, 
 <__main__.Card instance at 0x000000000273F4C8>, 
 <__main__.Card instance at 0x0000000002732E08>]

どうしたの?私たちは、Pythonに、 Cardインスタンスを表示する方法を教えてくれました。どうして明らかに忘れてしまったのでしょうか?

解決策(その2)

まあ、舞台裏の機械は、Pythonがリスト内の項目の文字列表現を取得したいときには少し違っています。それは、Pythonがこの目的のために__str__を気にしないことが判明しました。

代わりに、それは別の方法を探します__repr__それが見つからない場合は、それは「16進数の事」にフォールバックします。[2]

だから私は同じことをする2つの方法を作らなければならないと言っているのですか? 1つは自分のカードとそれが何らかのコンテナに入っているときに別のカードをprintたいときです。

いいえ、最初に、 __str____repr__両方の__str__を実装する場合は、クラスどのようなものになるかを見てみましょう:

class Card:
    special_names = {1:'Ace', 11:'Jack', 12:'Queen', 13:'King'}

    def __init__(self, suit, pips):
        self.suit = suit
        self.pips = pips

    def __str__(self):
        card_name = Card.special_names.get(self.pips, str(self.pips))
        return "%s of %s (S)" % (card_name, self.suit)

    def __repr__(self):
        card_name = Card.special_names.get(self.pips, str(self.pips))
        return "%s of %s (R)" % (card_name, self.suit)

ここで、二つの方法の実装__str____repr__ 、二つの方法を区別することを除いて、正確に同じである、 (S)によって返される文字列に追加さ__str__及び(R)によって返される文字列に付加される__repr__

__str__メソッドと同様に、 __repr__は引数を受け付けず、文字列を返します。

それぞれの場合にどのような方法が原因であるかを確認できます。

ace_of_spades = Card('Spades', 1)
four_of_clubs = Card('Clubs',  4)
six_of_hearts = Card('Hearts', 6)

my_hand = [ace_of_spades, four_of_clubs, six_of_hearts]

print(my_hand)           # [Ace of Spades (R), 4 of Clubs (R), 6 of Hearts (R)]

print(ace_of_spades)     # Ace of Spades (S)

__str__メソッドは、 Cardインスタンスを渡してprintときに呼び出され、 __repr__メソッドは、インスタンスのリストを渡してprint するときに呼び出されました。

この時点で、以前に行ったようにstr()を使ってカスタムクラスインスタンスから文字列を明示的に作成できるように、 repr()という組み込み関数を使ってクラスの文字列表現を明示的に作成することもできますrepr()

例えば:

str_card = str(four_of_clubs)
print(str_card)                     # 4 of Clubs (S)

repr_card = repr(four_of_clubs)
print(repr_card)                    # 4 of Clubs (R)

さらに、定義されていれば、メソッドを直接呼び出すこともできます(ただし、不明瞭で不必要な部分があります)。

print(four_of_clubs.__str__())     # 4 of Clubs (S)

print(four_of_clubs.__repr__())    # 4 of Clubs (R)

それらの複製機能について

Pythonの開発者は、同じ文字列をstr()repr()から返すようにしたい場合、メソッドを機能的に複製する必要があります。

その代わりに、その必要性を排除するための仕組みがあります。私はこの時点まであなたを詮索しています。これは、クラスが実装している場合ことが判明し__repr__方法ではなく、 __str__方法を、あなたがするそのクラスのインスタンスを渡すstr() (暗黙的または明示的かどうか)、Pythonはあなたにフォールバックします__repr__実装とそれを使用します。

したがって、明確にするために、次のバージョンのCardクラスを検討してください。

class Card:
    special_names = {1:'Ace', 11:'Jack', 12:'Queen', 13:'King'}

    def __init__(self, suit, pips):
        self.suit = suit
        self.pips = pips

    def __repr__(self):
        card_name = Card.special_names.get(self.pips, str(self.pips))
        return "%s of %s" % (card_name, self.suit)

このバージョンは__repr__メソッドのみを実装していることに注意してください。それにもかかわらず、 str()呼び出すとユーザフレンドリーなバージョンになります:

print(six_of_hearts)            # 6 of Hearts  (implicit conversion)
print(str(six_of_hearts))       # 6 of Hearts  (explicit conversion)

repr()呼び出しと同じように:

print([six_of_hearts])          #[6 of Hearts] (implicit conversion)
print(repr(six_of_hearts))      # 6 of Hearts  (explicit conversion)

概要

あなたのクラスインスタンスにユーザーフレンドリーな方法で「自分自身を公開」する権限を与えるには、少なくともクラスの__repr__メソッドを実装することを検討してください。メモリが提供されている場合、Raymond Hettingerの講演では、クラスが__repr__実装することが、Pythonのコードレビューを行う際に最初に__repr__ 1つであると述べています。単純な方法でデバッグステートメント、クラッシュレポート、またはログファイルに追加できる情報量は、デフォルトで与えられている手ごろな、そしてしばしば役立たない(タイプ、ID)情報と比較すると圧倒されます。

あなたがのために異なる表現をしたい場合は、例えば、容器の内側に、あなたは両方を実装することをお勧めします__repr____str__メソッドを。 (これらの2つの方法を以下ではどのように使い分けるかについての詳細はこちら)。

両方のメソッドが実装され、eval-round-tripスタイル__repr __()

class Card:
    special_names = {1:'Ace', 11:'Jack', 12:'Queen', 13:'King'}

    def __init__(self, suit, pips):
        self.suit = suit
        self.pips = pips

    # Called when instance is converted to a string via str()
    # Examples:
    #   print(card1)
    #   print(str(card1)
    def __str__(self):
        card_name = Card.special_names.get(self.pips, str(self.pips))
        return "%s of %s" % (card_name, self.suit)

    # Called when instance is converted to a string via repr()
    # Examples:
    #   print([card1, card2, card3])
    #   print(repr(card1))
    def __repr__(self):
        return "Card(%s, %d)" % (self.suit, self.pips)


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow