这将是一个简单的问题,因此它不会花费你太多时间向我解释,但它会帮助我(也可能是其他人)理解类和方法以及Python。
我的代码想要代表一个棋盘游戏,只需在一个有N个孔的棋盘上,这个棋盘可以容纳从0到N-1(以随机顺序)编号的大理石。
class MarblesBoard:
'''define the board game'''
def __init__(self, Board):
self._Board = Board
self._n = len(Board)
'''first type of move available: switch the first two marbles'''
def switch(Board):
Board[0], Board[1] = Board[1], Board[0]
return Board
'''second type of move available: move all the marbles by 1 space to the left'''
def rotate():
temp = Board[0]
for i in range (0, n-1):
Board[i] = Board[i+1]
Board[n-1] = temp
return Board
'''print the state'''
def __repr__(Board):
for i in range(0, len(Board)):
print self[i],
'''rest to be developed when this works'''
现在,我测试显示板和移动弹珠。所以我让
First = MarblesBoard([1,2,3,4])
First.rotate
并且只获得
<repr(<instancemethod at 0x104230410>) failed: AttributeError: MarblesBoard instance has no attribute '__len__'>
我知道有关此错误消息的类似问题。 AttributeError: Entry instance has no attribute '__len__'
我仍然不知道我的代码中是如何出现同样的错误的。您是否介意解释(一般情况下)属性&#34; len &#34;已建立,并可能建议如何在此代码中完成?
答案 0 :(得分:1)
当你这样做时:
First = MarblesBoard([1,2,3,4])
First.rotate
调用 __repr__
,因此可以在终端上回显对象的表示。这是你的(请注意,在它中打印是错误的,你应该只返回字符串,但纠正这个不在此范围内。):
def __repr__(Board):
for i in range(0, len(Board)):
print self[i],
您致电len(Board)
。这个参数Board
实际上是对象的实例。使用self
代替Pythonic。您尚未为__len__
定义len
函数来调用此对象,因此您会收到错误。
这是我要做的一些编辑的例子。首先从对象继承:
class MarblesBoard(object):
'''define the board game'''
接下来,我们只将类名称大写:
def __init__(self, board):
self._board = board
self._n = len(board)
最后,docstrings位于函数名和参数下面:
def switch(self):
'''first type of move available: switch the first two marbles'''
self.board[0], self.board[1] = self.board[1], self.board[0]
return self.board
答案 1 :(得分:1)
def __init__(self, Board):
self._Board = Board
self._n = len(Board)
'''first type of move available: switch the first two marbles'''
def switch(Board):
Board[0], Board[1] = Board[1], Board[0]
return Board
您似乎期望Board
方法中的switch
与Board
中的__init__
相同 - 它不是。任何方法的第一个参数是您正在使用的实例(所以,MarblesBoard
的实例,当您希望它是一个列表时) - 您给它的名称不会影响它,但是通常(正如您在__init__
中所做的那样)将其称为self
。
Board
中的__init__
是您实际传入的参数 - 列表。要将其与其他方法联系起来,您需要将其与self
相关联 - 您已经完成此操作,称为self._Board
。与任何变量名称或函数参数一样,您选择的名称不会影响功能,但是 - 再次 - 有些约定并将其称为self._board
(全部小写),而不是更常见。因此,您可以将以上两种方法重写为:
def __init__(self, board):
self._board = board
self._n = len(Board)
'''first type of move available: switch the first two marbles'''
def switch(self):
self._board[0], self._board[1] = self._board[1], self._board[0]
(请注意,您可能不希望从switch
返回任何内容,因为它会更改self
的状态。
这使我们了解问题的核心。 Python隐式调用__repr__
方法,你已经定义了这样的方法:
def __repr__(Board):
for i in range(0, len(Board)):
print self[i],
同样的事情正在发生:当Board
为MarblesBoard
时,您希望len(Board)
成为一个列表。拨打MarblesBoard.__len__
然后尝试拨打self[i]
,这不存在。您还尝试过调用MarblesBoard.__getitem__
,如果之前还没有它,那么这也是一个错误(因为它会调用另一种魔术方法,MarblesBoard
,您也可以使用def __repr__(self):
for i in range(0, len(self._board)):
print self._board[i]
#39; t定义)。一次解决这两个问题的方法就是完全按照我们上面的做法进行,并通过{{1}}实例进入列表:
{{1}}
会工作吗?但请注意,此配方仍然不是Pythonic - 一旦您的代码有效,您可能需要考虑将其发布到codereview.SE。