2012-04-01 25 views
8

[对不起,我是Python新手。虽然这似乎是一个非常基本的问题,但在向观众提问之前,我尽了我的尽职调查,试图避免真正愚蠢的问题]。从python函数中返回一个左值

我想弄清楚从函数返回一个l值的正确方法。假设我有一个包含64个对象的容器,并且我希望能够返回对这些对象的引用。

class ChessBoard: 
    def __init__(self): 
     self.squares = [None for x in range(64)] 

    square(row, col): 
     return self.squares(row*8+col) <---- I'd like this to be l-value 

然后,从类之外我想:

board = ChessBoard() 
board.square(0,0) = Piece(Shapes.ROOK, Colors.White) <-- I'm getting an error here 
board.square(0,1) = Piece(Shapes.BISHOP, Colors.White) 
... etc. 

所以,我想功能“在”返回一个左值(喜欢的东西在C++中的引用),但我可以在语言中找不到任何类似于引用或指针的东西。如果我在每个包含一块的正方形中存储了一个列表,我可以这样做:board.square(0,0)[0] = piece - 但它看起来很疯狂(或者可能不是 - 正如我所说的,我是新来的语言)。

你会如何处理这个数据结构?

回答

8

在Python中,的一切是一个参考。唯一的问题是None不可变的,所以你不能使用返回的引用来改变这个值。

你也不能重写赋值操作符,所以你不会得到这种特殊的行为。但是,一个良好的和非常灵活的解决方案是重写__setitem____getitem__方法来实现认购运营商([])为类:

class ChessBoard(object): 
    def __init__(self): 
    self.squares = [None] * 64 

    def __setitem__(self, key, value): 
    row, col = key 
    self.squares[row*8 + col] = value 

    def __getitem__(self, key): 
    row, col = key 
    return self.squares[row*8 + col] 

用法:

>>> c = ChessBoard() 
>>> c[1,2] = 5 
>>> c[1,2] 
5 
+0

注意,定义在3.X稍微难看,因为元组参数列表拆包的特例去挪威蓝色的方式。你必须定义'def __setitem __(self,row_col,value):row,col = row_col; self.squares [row * 8 + col] = value'。 – delnan 2012-04-01 14:39:06

+0

@delnan:谢谢,我改变了它,因为其余的版本是不可知的。我认为删除此功能的选择是不幸的,如果明智地使用它可能会非常有用。 – 2012-04-01 14:40:30

+0

谢谢@尼克拉斯 – Uri 2012-04-01 18:19:04

1

正如尼古拉斯指出,你不能返回一个l值。

然而,除了覆盖订阅,您也可以使用properties(描述符的应用:http://docs.python.org/howto/descriptor.html)创建一个对象的属性,它读取时,或分配到,运行的代码。

+0

虽然这并没有解决这个问题,因为没有属性设置来拦截这里。它可以用于启用诸如'board.square(0,0).value = Piece(...)'之类的东西。 – 2012-04-01 14:56:06

+0

@NiklasB。这就是为什么我不提供任何代码。 – Marcin 2012-04-01 15:06:00

+1

谢谢@Marcin – Uri 2012-04-01 18:19:48

1

(不回答你的问题的称号,但你的“你会如何处理这个数据结构?”的问题:)为您的数据结构的更Python的解决方案将使用列表的列表:

# define a function that generates an empty chess board 
make_chess_board = lambda : [[None for x in xrange(8)] for y in xrange(8)] 

# grab an instance 
b = make_chess_board() 

# play the game! 
b[0][0] = Piece(Shapes.ROOK, Colors.White) 
b[0][1] = Piece(Shapes.BISHOP, Colors.White) 

# Or use tuples: 
b[0][0] = (Shapes.ROOK, Colors.White) 
b[0][1] = (Shapes.BISHOP, Colors.White) 
1

你可以尝试这样的事情,在具有成本把假的[:]索引围:

class Board: 
    def __init__(self): 
     self.squares=[None for x in range(64)] 
    def square(self, row, col): 
     squares=self.squares 
     class Prox: 
      def __getitem__(self, i): 
       return squares[row*8+col] 
      def __setitem__(self, i, v): 
       squares[row*8+col]=v 
     return Prox() 

然后,你可以做

b=Board() 
b.square(2,3)[:]=Piece('Knight') 
if b.square(x,y)[:] == Piece('King') ... 

等等。它实际上并不重要,你放在[]中,它只是一些东西。

(得到了来自代理Perl6的想法使用要做到这一点)

+0

你可以请你从哪里获得这个想法的来源? – Andres 2014-01-28 21:36:34