实例没有属性“__len__”

instance has no attribute '__len__'

这将是一个简单的问题,因此您不会花太多时间向我解释,但它会帮助我(可能还有其他人)了解一些关于 类 和方法以及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__'

我还是不明白为什么我的代码中会出现同样的错误。你介意解释一下(一般来说)属性“len”是什么时候建立的,并且可能会建议如何在这段代码中完成它?

当你这样做时:

First = MarblesBoard([1,2,3,4])
First.rotate

__repr__ 被调用,因此对象的表示可以在您的终端上回显。这是你的(请注意,打印在其中是错误的,你应该只是 return 字符串,但更正它超出了这个范围。):

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

接下来,我们只将class个名字大写:

    def __init__(self, board):
        self._board = board
        self._n = len(board)

最后,文档字符串位于函数名称和参数下方:

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

您似乎期望 switch 方法中的 Board__init__ 中的 Board 相同 - 但事实并非如此。任何方法的第一个参数是您正在使用的实例(因此,MarblesBoard 的实例,当您期望它是一个列表时) - 您给它的名称不会影响它,但它是按照惯例(正如您在 __init__ 中正确完成的那样)将其称为 self

__init__中的Board是你实际传入的参数——一个列表。要以其他方法取回它,您需要将它附加到 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]

(请注意,您可能 不想 想要 return 来自 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]

会起作用的。但是,请注意,此公式仍然不是很 Pythonic - 一旦您的代码起作用,您可能需要考虑将其发布到 codereview.SE.