类交叉引用?

4

我来自C++背景,对于在Python中没有指针的整个概念感到有些迷茫。或者至少不太清楚。 例如,我想使用Python中的OOP创建一个井字棋游戏。我有几个类如下:

class Game(object):
    def __init__(self, player1, player2):
        self.board = [['','',''],
                      ['','',''],
                      ['','','']]
        self.players = [player1, player2]

class Player(object):
    def __init__(self, game, marking):
        self.game = game
        self.marking = marking  # either 'X' or 'O'

显然,游戏需要参考两个玩家,并且玩家也是游戏的一部分,因此应该有一个对游戏的引用。然而,上面的代码无法工作,因为我没有办法先创建一个玩家而不创建一个游戏。但是要创建一个游戏,我需要两个玩家。
我可以稍后添加这些引用,例如:player.game = some_game_reference,但这似乎不符合Python的风格,并且难以跟进。
最好、最符合Python风格的方法是什么?

1
objectplayer1 等等都是指针。它们不是值,就像在 C++ 中一样。 - user2100815
6
玩家需要知道游戏的原因是什么?游戏由棋盘和两个玩家组成。游戏知道轮到哪个玩家以及棋盘的状态,但是玩家不需要知道游戏的情况。 - Mike Scotty
1
在Python中,通常很少需要两个对象彼此引用。当你确实需要这样做时,通常其中一个对象包含另一个对象,并且通常会直接将自己的引用设置到另一个对象上(此时对象已经紧密耦合)。 - spectras
1
如果您创建了一个游戏列表,您可以查询每个游戏是否包含特定的玩家。这样,一个玩家甚至可以参加多个游戏,而不仅仅局限于一个游戏。或者构建一个名为“Casino”的类来跟踪哪个玩家正在玩哪个游戏。 - Mike Scotty
2
说实话,在Python中你根本不应该考虑指针。它是一种比指针高级得多的语言。Python没有实际的指针类型,但是在“引擎盖下”,你可以认为Python传递指向Py_Object结构体的指针。但是说实话,你应该阅读Ned Batchelder的《关于Python名称和值的事实与神话》(Facts and Myths about Python names and values)。 - juanpa.arrivillaga
显示剩余3条评论
1个回答

3

您可以只让一个类更新其参数。例如,先创建玩家,然后让游戏使用自身更新玩家:

class Game(object):
    def __init__(self, player1, player2):
        self.board = [['','',''],
                      ['','',''],
                      ['','','']]
        self.players = [player1, player2]
        player1.game = self
        player2.game = self
        player1.marking = 'X'
        player2.marking = 'O'  

# Neither game nor marking make sense to set initially, until
# the players are added to a game.
class Player(object):
    def __init__(self):
        pass

p1 = Player()
p2 = Player()

g = Game(p1, p2)

(是否需要这种耦合方式,正如其他人指出的那样,是一个单独的设计问题。)

只是为了展示另一种方向同样可行:

class Player(object):
    def __init__(self, game, marking):
        self.game = game
        self.marking = marking
        game.players.append(self)

class Game(object):
    def __init__(self):
        self.board = [['','',''],
                      ['','',''],
                      ['','','']]

g = Game()
p1 = Player(g, 'X')
p2 = Player(g, 'O')

希望您能同意,游戏为每个玩家分配一个标记会更加合理。在这里,您可以尝试将多于2个玩家添加到游戏中,或者添加两个 X 或两个 O 玩家。


这非常有用,谢谢。我将查看是否发布了其他答案,但似乎这解决了我的问题。我不知道我可以将self分配给变量。您会说有更好的方法吗?上面的评论指出通常不需要类似这样的东西,但在我看来,这种方式可以创建某种图表(数据结构),并且可能每个玩家都有多个游戏。谢谢! - Max Smith
1
这真的取决于你的应用程序结构,但我同意你应该努力使Player类不需要任何有关玩家参与的游戏信息。至于self,这个名称没有什么特别之处;你可以使用任何想要的名称,但是self是常规用法。它只是指代作为任何实例方法的(隐式)第一个参数传递的对象。任何方法调用obj.method(...)等效于type(obj).method(obj,...);参数self(或任何你使用的名称)绑定到obj - chepner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接