访问在其他文件中实例化的类对象的变量

时间:2017-04-04 16:43:35

标签: python python-3.x oop

我在Python上非常环保,一直在寻找我特定问题的答案。虽然我不确定它是否是一个特定于Python的问题,或者我只是让我的OOP /设计模式混淆。

我有三个文件:main.pyboard.pyplayer.py。董事会和玩家每人只持有一级玩家和董事会,主要只是开始游戏。

然而,当他们被添加到棋盘时,我正在努力验证玩家的位置。我想要的是在main.py中实例化棋盘和连续的新玩家对象,但是当新玩家被添加到棋盘时,检查player.py中的棋盘大小,以确保玩家不是创造之外的界限。

现在我在尝试访问getX() missing 1 required positional argument: 'self'内的电路板尺寸时遇到TypeError(player.py)。

最有可能的原因是董事会未在该范围内实例化。但是,如果我在将被视为新对象的范围中实例化它,那么它会赢吗?如果我将棋盘作为变量传递给玩家,那肯定会被视为不好的做法,那不是吗?

那么如何从另一个类访问一个类的实例变量呢?

3 个答案:

答案 0 :(得分:0)

我不知道这是否会有所帮助,但我发了一篇关于如何使用Pickle导入保存和加载的帖子。在保存功能中,它返回我创建的Player类。它可能对你有帮助,也可能没有。无论如何Here是链接。

答案 1 :(得分:0)

你的问题是询问一个名为"依赖注入的概念。"你应该花一些时间来阅读它。它详细说明了将一个对象提供给另一个想要与之交互的对象的方法。虽然这里的内容过于宽泛,但这里有一些基础知识:

  1. 您可以让您关心的所有对象都是全局的,或者包含在全局容器中。他们都可以看到对方并在必要时互相交流。这不是面向对象的,并不是最佳实践。它很脆弱(所有物体紧密地结合在一起,很难改变或替换它们),并且它不是一个好的测试设计。但是,如果不是一个好的选择,这是一个有效的选择。
  2. 您可以让彼此关心的对象相互传递。这将是所有对象之外的东西的责任(在您的情况下,基本上是您的主要功能)。您可以在每个关心的方法中传递对象(例如board.verify_player_position(player1))。这很好用,但您可能会发现自己将相同的参数传递给几乎所有函数。或者您可以通过设置调用(例如board.set_player1(player1))或构造函数(例如board = Board(player1, player2))设置参数。其中任何一个在功能上几乎相同,它只是一个似乎最适合你的问题。您仍然可以将对象绑定得非常紧密。这可能是不可避免的。但至少测试更容易。您可以创建存根类并将它们传递到适当的位置。 (请记住,python适用于鸭子打字:"如果它像鸭子一样走路,像鸭子一样呱呱叫,那么它就是鸭子。"你可以制作与你的功能相同的测试代码棋盘和玩家类,用它来测试你的功能。)
  3. 一个常见的模式是让这些对象相当愚蠢,并且有一个" game_logic"或其他一些控制器。这将给出董事会和两名球员的实例,并负责维护游戏的所有规则。然后你的main函数基本上会创建棋盘和玩家,并简单地将它们传递给你的控制器实例。如果你朝着这个方向前进,我不确定你需要多少代码才能让你的玩家或棋盘拥有,所以你可能不喜欢这种风格。
  4. 还有其他模式可以做到这一点,但这些是一些更基本的模式。

    回答您的直接问题:是的,您看到的错误是因为您尝试调用类函数,并且您需要它在一个对象上。是的,在这种情况下实例化会很糟糕。但是没有,将一个类的实例传递给另一个类并不是一件坏事。如果他们不与某些东西互动,那么他们就没有用的东西;大多数对象需要在某些时候与其他对象进行交互。

    你提到你有可用的代码,但在进入编码之前稍微考虑一下你的对象交互是一件好事。这就是问题所在:你想要player1.check_valid_position(board)board.check_player(player1),还是rules.validate_move(player,some_kind_of_position_variable)`。它们都是有效的,它们都有相互关联的对象;这只是一个让你最有意义的问题。

答案 2 :(得分:0)

如果没有看到某些代码,很难知道您的确切问题,但我希望这很有用!

class Player:
    def __init__(self, x, y, player_id):
        self.x = x
        self.y = y
        self.id = player_id

class Board:
    def __init__(self, width, height):
        self.width = width
        self.height = height
        self.players = {}

    def add_player(self, player):
        """keep track of all the players"""
        self._validate_player(player)

        # add the player to a dict so we can access them quickly
        self.players[player.id] = player

    def _validate_player(self, player):
        """whatever validation you need to do here"""
        if player.x < 0 or player.x >= self.width:
            raise ValueError("The player didn't land on the board! Please check X")

        if player.y < 0 or player.y >= self.height:
            raise ValueError("The player didn't land on the board! Please check Y")

        # whatever other checks you need to do

        # player is in a valid location!


def main():
    # we can make as few or as many players as we'd like!
    p1 = Player(10, 20, 0)
    p2 = Player(-1, 10, 1)  # invalid player

    board = Board(50, 50) # we only need to make one board

    board.add_player(p1)
    board.add_player(p2)  # value error

    running = True
    while running:  # simple game loop
        player.take_turn()  # maybe prompt user to input something
        board.update_players()  # update player positions
        board.display()
        running = board.keep_playing()  # check for win state
        # whatever code you want to run

if __name__ == "__main__":
    main()

这里我们通过分配x和y位置创建一个Player的实例,在这种情况下也是一个玩家ID,我们可以在需要时使用它来获取该玩家。如果只有一个玩家,我们可以做一些像board.player。

在我的示例中,当提供无效的播放器时会引发ValueError,当然,如果播放器无效,您可以执行任何您想要的操作,您的游戏也可以包含任意数量的其他案例玩家无效。

我已经为一些可能对棋盘游戏有意义的方法添加了一些方法调用。

作为旁注,在python中,您通常不需要编写getter / setter,完全可以直接访问Class字段。

player.x = 10 如果是player.y == 11:等等。

如果您需要验证可能属于getter / setter的某种类型,可以使用@property装饰器。