实例没有属性'__len__'

时间:2015-01-29 01:53:16

标签: python attributes

这将是一个简单的问题,因此它不会花费你太多时间向我解释,但它会帮助我(也可能是其他人)理解类和方法以及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;已建立,并可能建议如何在此代码中完成?

2 个答案:

答案 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方法中的switchBoard中的__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],

同样的事情正在发生:当BoardMarblesBoard时,您希望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