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]]
私は何が欠けていますか?そして、私はそれ以外のしつこい価値があることは何をしていますか? :)
Pythonには、オブジェクトを文字列に変換する2つの異なる方法があります:str()
とrepr()
。オブジェクトを印刷するにはstr()
を使用します。オブジェクトを含むリストを印刷するには、リスト自体にstr()
を使用しますが、list.__str__()
の実装は個々のアイテムに対してrepr()
を呼び出します。
したがって、__repr__()
も上書きする必要があります。シンプルな
__repr__ = __str__
クラス本体の最後でトリックを行います。
PythonのJavaに対する無限の優位性のため、Pythonにはoneではなく、two toString操作があります。
1つは__str__
、もう1つは__repr__
です。
__str__
は人間が読める文字列を返します。 __repr__
は内部表現を返します。
__repr__
は、repr(obj)
を呼び出すか、バッククォート`obj`
を使用して、オブジェクトで呼び出すことができます。
リストや他のコンテナクラスを印刷する場合、含まれる要素は__repr__
を使用して印刷されます。
「オブジェクト」ではなく、人間が読める形式の出力を提供します。例:
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
さて、コンテナオブジェクトの__str__
メソッドは、repr
ではなく、コンテンツにstr
を使用します。そのため、__repr__
の代わりに__str__
を使用できます。結果としてIDを使用しているように見えます。
別の answer で指摘したように、そして PEP 314 で読むことができるように、str
のlist
は各項目__repr__
を呼び出します。その部分についてできることはあまりありません。
__repr__
を実装すると、より記述的なものが得られますが、正しく実装した場合は、期待したとおりにはなりません。
高速だが間違っているソリューションは、__repr__
を__str__
にエイリアスすることです。
__repr__
を__str__
に無条件に設定しないでください。 __repr__
は 表現、同じ値を持つオブジェクトを再作成するために使用できる有効なPython式のように見えるはずです を作成する必要があります。この場合、これは2
ではなくNode(2)
になります。
__repr__
を適切に実装すると、オブジェクトを再作成できます。この例では、neighours
やdistance
などの他の重要なメンバーも含まれている必要があります。
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)
を使用すると、オブジェクトを再作成して同等性を確認できます。
__str__
は、オブジェクトに文字列表現が必要な場合にのみ呼び出されます。
たとえば、str(uno)
、print "%s" % uno
、またはprint uno
ただし、__repr__
と呼ばれる別の魔法のメソッドがあります。これはオブジェクトの表現です。オブジェクトを明示的に文字列に変換しない場合は、表現が使用されます。
これを実行すると、uno.neighbors.append([[str(due),4],[str(tri),5]])
は期待どおりに動作します。
クラスに関すること、および妨げのないグローバル変数をクラス内のある値に設定することは、グローバル変数が実際に格納するのは、実際に値が格納されるメモリ位置への参照であるということです。
出力に表示されているものはこれを示しています。
strメソッドと印刷のしくみのために使用した初期グローバル変数で値を確認して問題なく印刷を使用できる場合、リストではこれを行うことができませんが、そのリスト内の要素に格納されているのは、値のメモリ位置への参照にすぎないためです。詳細については、エイリアスを参照してください。
さらに、リストを使用して、エイリアスとそうでないものを追跡できない場合、エイリアスリストで値を変更すると、元のリスト要素の値を変更していることに気付くかもしれません。リストまたはリスト内の要素に等しいリスト要素、新しいリストはメモリ位置への参照のみを格納します(実際にはその新しい変数に固有の新しいメモリ空間を作成しません)。これは、ディープコピーが便利な場所です!