web-dev-qa-db-ja.com

Pythonのリストの__str__について混乱

Javaのバックグラウンドから来ると、__str__はPythonバージョンのtoStringのようなものであることがわかります(Pythonが古い言語であることに気付きました)。

そのため、次のように__str__メソッドとともに小さなクラスを定義しました。

class Node:

    def __init__(self, id):
        self.id = id
        self.neighbours = []
        self.distance = 0


    def __str__(self):
        return str(self.id)

次に、そのインスタンスをいくつか作成します。

uno = Node(1)    
due = Node(2)    
tri = Node(3)    
qua = Node(4)

現在、これらのオブジェクトの1つを印刷しようとするときの予期される動作は、関連付けられた値が印刷されることです。これも起こります。

print uno

利回り

1

しかし、私が次のことをすると:

uno.neighbours.append([[due, 4], [tri, 5]])

その後

print uno.neighbours

私は得る

[[[<__main__.Node instance at 0x00000000023A6C48>, 4], [<__main__.Node instance at 0x00000000023A6D08>, 5]]]

期待していたところ

[[2, 4], [3, 5]]

私は何が欠けていますか?そして、私はそれ以外のしつこい価値があることは何をしていますか? :)

109

Pythonには、オブジェクトを文字列に変換する2つの異なる方法があります:str()repr()。オブジェクトを印刷するにはstr()を使用します。オブジェクトを含むリストを印刷するには、リスト自体にstr()を使用しますが、list.__str__()の実装は個々のアイテムに対してrepr()を呼び出します。

したがって、__repr__()も上書きする必要があります。シンプルな

__repr__ = __str__

クラス本体の最後でトリックを行います。

133
Sven Marnach

PythonのJavaに対する無限の優位性のため、Pythonにはoneではなく、two toString操作があります。

1つは__str__、もう1つは__repr__です。

__str__は人間が読める文字列を返します。 __repr__は内部表現を返します。

__repr__は、repr(obj)を呼び出すか、バッククォート`obj`を使用して、オブジェクトで呼び出すことができます。

リストや他のコンテナクラスを印刷する場合、含まれる要素は__repr__を使用して印刷されます。

36
Hans Then

「オブジェクト」ではなく、人間が読める形式の出力を提供します。例:

class Pet(object):

    def __init__(self, name, species):
        self.name = name
        self.species = species

    def getName(self):
        return self.name

    def getSpecies(self):
        return self.species

    def Norm(self):
        return "%s is a %s" % (self.name, self.species)

if __name__=='__main__':
    a = Pet("jax", "human")
    print a 

返す

<__main__.Pet object at 0x029E2F90>

一方、「str」のコードは何か異なるものを返します

class Pet(object):

    def __init__(self, name, species):
        self.name = name
        self.species = species

    def getName(self):
        return self.name

    def getSpecies(self):
        return self.species

    def __str__(self):
        return "%s is a %s" % (self.name, self.species)

if __name__=='__main__':
    a = Pet("jax", "human")
    print a 

戻り値:

jax is a human
24
jax

さて、コンテナオブジェクトの__str__メソッドは、reprではなく、コンテンツにstrを使用します。そのため、__repr__の代わりに__str__を使用できます。結果としてIDを使用しているように見えます。

9
user1675187

質問への回答

別の answer で指摘したように、そして PEP 314 で読むことができるように、strlistは各項目__repr__を呼び出します。その部分についてできることはあまりありません。

__repr__を実装すると、より記述的なものが得られますが、正しく実装した場合は、期待したとおりにはなりません。

適切な実装

高速だが間違っているソリューションは、__repr____str__にエイリアスすることです。

__repr____str__に無条件に設定しないでください__repr__表現、同じ値を持つオブジェクトを再作成するために使用できる有効なPython式のように見えるはずです を作成する必要があります。この場合、これは2ではなくNode(2)になります。

__repr__を適切に実装すると、オブジェクトを再作成できます。この例では、neighoursdistanceなどの他の重要なメンバーも含まれている必要があります。

incompleteの例:

class Node:

    def __init__(self, id, neighbours=[], distance=0):
        self.id = id
        self.neighbours = neighbours
        self.distance = distance


    def __str__(self):
        return str(self.id)


    def __repr__(self):
        return "Node(id={0.id}, neighbours={0.neighbours!r}, distance={0.distance})".format(self)
        # in an elaborate implementation, members that have the default
        # value could be left out, but this would hide some information


uno = Node(1)    
due = Node(2)    
tri = Node(3)    
qua = Node(4)

print uno
print str(uno)
print repr(uno)

uno.neighbours.append([[due, 4], [tri, 5]])

print uno
print uno.neighbours
print repr(uno)

__eq____ne__または__cmp__の適切な実装と一緒にprint repr(uno)を使用すると、オブジェクトを再作成して同等性を確認できます。

6
trapicki

__str__は、オブジェクトに文字列表現が必要な場合にのみ呼び出されます。

たとえば、str(uno)print "%s" % uno、またはprint uno

ただし、__repr__と呼ばれる別の魔法のメソッドがあります。これはオブジェクトの表現です。オブジェクトを明示的に文字列に変換しない場合は、表現が使用されます。

これを実行すると、uno.neighbors.append([[str(due),4],[str(tri),5]])は期待どおりに動作します。

4
Burhan Khalid

クラスに関すること、および妨げのないグローバル変数をクラス内のある値に設定することは、グローバル変数が実際に格納するのは、実際に値が格納されるメモリ位置への参照であるということです。

出力に表示されているものはこれを示しています。

strメソッドと印刷のしくみのために使用した初期グローバル変数で値を確認して問題なく印刷を使用できる場合、リストではこれを行うことができませんが、そのリスト内の要素に格納されているのは、値のメモリ位置への参照にすぎないためです。詳細については、エイリアスを参照してください。

さらに、リストを使用して、エイリアスとそうでないものを追跡できない場合、エイリアスリストで値を変更すると、元のリスト要素の値を変更していることに気付くかもしれません。リストまたはリスト内の要素に等しいリスト要素、新しいリストはメモリ位置への参照のみを格納します(実際にはその新しい変数に固有の新しいメモリ空間を作成しません)。これは、ディープコピーが便利な場所です!

1
Tommy W.