2015-06-07 3 views
2

Я пытаюсь улучшить игру «броненосец», которую вы делаете в курсе codecademy для python, и я решил, что первым шагом будет реализация классов.__str__ для печати строк по методу

Мой ожидаемый результат от кода составляет пять строк от O O O O O. Это достижение, когда я использую только оператор печати внутри для цикла, но он выдает ошибку, заявив:

Traceback (most recent call last): 
File "D:/PythonProjects/Battleship/Main.py", line 21, in <module> 
    print(board) 
TypeError: __str__ returned non-string (type NoneType) 

И когда я покину код, как это не бросать и ошибки, но печатает только одну строку выходов

код в вопросе:

class Board(object): 
    """Creates the game board""" 
    board = [] 

    def __init__(self, size): 
     self.size = size 
     for x in range(size): 
      self.board.append(["O"] * size) 

    def __str__(self): 
     for row in self.board: 
      display = (" ".join(row)) 

     return display 

board = Board(5) 
print(board) 
+0

Ну это потому, что вы присваиваете новый строка для отображения в цикле. –

+0

Вы должны конкатенировать '\ n' до конца каждой строки, чтобы получить новую строку. Это «новый символ линии». – Roope

+0

О, ладно, теперь я понимаю. Так просто сейчас, когда кто-то указал мне на это! Спасибо! – Bitterguy

ответ

2

ваш метод __str__ присваивает новое значение display с каждой итерации цикла. Вместо этого вы могли бы сделать что-то вроде:

def __str__(self): 
    accumulator = "" 
    for row in self.board: 
     accumulator += " ".join(row) + "\n" 
    return accumulator 

Или более лаконично

def __str__(self): 
    return "\n".join([" ".join(row) for row in self.board]) 

В полной стороне от кого-то, кто предназначен это снова и снова, чтобы помочь каждому новый набор студентов CS вдаваясь в Интро ООП , этот класс становится намного проще, если он наследует от list. Это контейнер для списков, которые описывают игровое поле - сделать это сам список ....

class Board(list): 
    def __init__(self, size): 
     """Square board of length `size`""" 
     for row in range(size): 
      self.append(["O"] * size) 

    def __str__(self): 
     return "\n".join([" ".join(row) for row in self]) 
+1

* «Это контейнер для списков, которые описывают игровое поле» * - Просто потому, что он * использует * список для хранения своих данных, который не делает его списком. Плата, имеющая фиксированное количество строк и специальный набор разрешенных взаимодействий, не является списком. Наследуя список, вы делаете его списком и наследуете весь интерфейс списка со всеми его методами манипуляции, которые здесь не подходят. – poke

+0

Во второй раз. Контейнер списков не является специализированным списком. Вам стыдно за то, что вы учили студентов НОБ-CS. – martineau

2

Прежде всего, вы не должны использовать свойство класса для board. Это позволит обмениваться экземпляром во всех экземплярах Board, поэтому вы продолжаете добавлять в тот же список. Вместо этого создайте новый список для каждого объекта вы создаете:

class Board(object): 
    def __init__(self, size): 
     self.size = size 
     self.board = [] 
     for x in range(size): 
      self.board.append(["O"] * size) 

Теперь, чтобы ответить на ваши проблемы, вы не должны на самом деле получить эту ошибку типа, потому что в то время как вы держите перезапись display в петле в __str__, это получить по крайней мере одно значение, которое не равно None, при условии, что board не пуст (чего нет в вашем примере).

Но то, что вы хотите сделать вместо этого собрать все строки и присоединиться к ним с новой строки:

def __str__(self): 
    display = [] 
    for row in self.board: 
     display.append(" ".join(row)) 
    return '\n'.join(display) 

Или в одной строке:

def __str__(self): 
    return '\n'.join([' '.join(row) for row in self.board]) 
+0

Я думаю, вы должны были ответить на вопрос в первую очередь. Вполне возможно, что OP никогда не заметит вторую проблему - даже если вы правы в этом, потому что это не похоже на то, что в игре есть более одного экземпляра 'Board'. Наконец, '__str __()' можно немного оптимизировать, чтобы просто «вернуть» \ n ".join (("" .join (строка) для строки в self.board)) '- нет необходимости создавать временный список строк только для подачи на внешнее' join() '. – martineau

+0

@martineau Это неверно. Присоединение к пониманию списка [более эффективно, чем присоединение к выражению генератора] (http://stackoverflow.com/a/9061024/216074); вы всегда должны использовать список. И хотя я согласен, я не могу помочь, что сначала не смог опубликовать свой ответ; более длинные ответы, как правило, требуют больше времени для написания. – poke

+0

Я не знал, что 'join()' с генератором является аномалией общего правила их эффективности. Спасибо за это. Однако мне хорошо известно, что часто требуется больше времени для получения более полных (и лучших) ответов. В этом случае то, что я имел в виду, было в вашем ответе, я думаю, вы должны сначала ответить на вопрос OP, а затем упомянуть проблему дизайна класса. – martineau

Смежные вопросы