Смутно о __str__ в Python

Исходя из фона Java, я понимаю, что __str__ - это что-то вроде версии toString на Python (хотя я понимаю, что 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)

Теперь ожидаемое поведение при попытке печати одного из этих объектов заключается в том, что его связанное значение печатается. Это также происходит.

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]]

Что мне не хватает? И что же я делаю?:)

Ответ 1

Python имеет два разных способа преобразования объекта в строку: str() и repr(). При печати объекта используется str(); печать списка, содержащего объект, использует str() для самого списка, но реализация list.__str__() вызывает repr() для отдельных элементов.

Поэтому вы также должны перезаписать __repr__(). Простой

__repr__ = __str__

в конце тела класса сделает трюк.

Ответ 2

Из-за бесконечного превосходства Python над Java у Python нет ни одной, ни двух операций toString.

Один __str__, другой __repr__

__str__ вернет читаемую пользователем строку. __repr__ вернет внутреннее представление.

__repr__ может быть вызван на объект, вызвав repr(obj) или используя обратные ссылки `obj`.

При печати списков, а также других классов контейнеров содержащиеся элементы будут напечатаны с использованием __repr__.

Ответ 3

Он обеспечивает читаемую пользователем версию вывода скорее "Объект": Пример:

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

Ответ 4

Ну, методы контейнерных объектов __str__ будут использовать repr для их содержимого, а не str. Таким образом, вы можете использовать __repr__ вместо __str__, видя, как вы используете идентификатор в качестве результата.

Ответ 5

__str__ вызывается только тогда, когда требуется строковое представление для объекта.

Например str(uno), print "%s" % uno или print uno

Однако существует еще один магический метод под названием __repr__, это представление объекта. Если вы явно не преобразовываете объект в строку, тогда используется представление.

Если вы сделаете это uno.neighbors.append([[str(due),4],[str(tri),5]]), он будет делать то, что вы ожидаете.

Ответ 6

Вещь о классах и задание необремененных глобальных переменных, равных некоторому значению внутри класса, заключается в том, что то, что хранит ваша глобальная переменная, на самом деле является ссылкой на местоположение памяти, которое фактически хранится.

То, что вы видите на своем выходе, свидетельствует об этом.

Если вы можете увидеть значение и использовать печать без проблем на исходных глобальных переменных, которые вы использовали из-за метода str и того, как работает печать, вы не сможете это сделать со списками, потому что то, что хранится в элементах в этом списке, - это просто ссылка на ячейку памяти значения - чтение на псевдонимах, если вы хотите узнать больше.

Кроме того, при использовании списков и потери пути к тому, что является псевдонимом, а что нет, вы можете обнаружить, что вы меняете значение исходного элемента списка, если вы меняете его в списке псевдонимов - потому что снова, когда вы устанавливаете элемент списка, равный списку или элементу в списке, новый список сохраняет только ссылку на ячейку памяти (она фактически не создает новое пространство памяти, специфичное для этой новой переменной). Именно здесь вам пригодится deepcopy!

Ответ 7

print self.id.__str__() будет работать для вас, хотя это и не так полезно для вас.

Ваш метод __str__ будет более полезен, когда вы скажете, что хотите распечатать представление сетки или структуры, как ваша программа развивается.

print self._grid.__str__()

def __str__(self):
    """
    Return a string representation of the grid for debugging.
    """
    grid_str = ""
    for row in range(self._rows):
        grid_str += str( self._grid[row] )
        grid_str += '\n'
    return grid_str