0

我正在使用一个名为 test.py 的文件测试我的两个类。我只是在学习编程,所以这只是一个练习程序。有一个地图集(地图),我可以在一张地图中放置多个“机器人”。

#test.py
from Atlas import Atlas
atlas = Atlas()
atlas.add_robot('rbt1')


#atlas.py
from Robot import Robot

class Atlas:

    def __init__(self):
        ...

    def add_robot(self, robot, zone = 'forrest'):
        self.robot = Robot(robot)
        print 'added robot %s to %s' % (robot, zone)


#robot.py
class Robot():

    def __init__(self, rbt, zone = 'forrest'):
        self.name = rbt
        print "%s initiated" % rbt

    def step(self, direction):
        ...

我使用代码“atlas.add_robot('rbt1')”将一个新机器人放入图集中。

我希望能够使用 test.py 中的“rbt1.step('left')”等命令来控制机器人。

4

3 回答 3

3

您应该在 test.py 中使用 制作您的机器人newRobot = Robot('rbt1'),然后使用atlas.add_robot(newRobot). 为此,我们传入一个完整的机器人,而不是机器人名称。Atlas 不应该尝试初始化机器人,因为它是 Atlas。它应该只关心 Atlases 做了什么:跟踪机器人的位置。

在编程中学习的一个好概念是允许哪些代码段接触某些东西。在这种情况下,我们将在 test.py 中创建机器人(以便我们可以触摸它),然后将其传递给 Atlas(以便 Atlas 可以触摸它)。这实际上是您问题的核心。以下是处理此问题的一些一般方法:

  • 重构你的代码,通过改变控制流,所以你没有这个问题(就像我在下面的演示)
  • 传入参数/访问器 - 要求对象为您提供与您所知道的匹配的机器人(在本例中为名称)
  • 浅层数据结构 - Atlas 将是一个浅层外壳,其行为类似于字典,您只需将其视为字典(而不是在yourAtlas.robotsToZones(...)下面做)
  • 滥用全局变量 - 永远不要这样做,这是可怕的编程
  • 闭包 - 如果您在函数内部定义一个函数(甚至可能是一个类内部的一个类,但这会变得很难看),内部函数可以访问外部函数中的变量,尽管您必须nonlocal在 python 中使用关键字来声明您的意图做这个

要更改控制流,以免出现此问题:通过传入一个完整的 Robot,Atlas 可以变得更加灵活。毕竟是阿特拉斯。为什么 Atlas 会负责制造机器人?

from collections import *

class Atlas(object):
    def __init__(self):
        self.zones = defaultdict(set)

    def add_robot(self, robot, zone='forest')
        self.robots[zone].add(robot)

或者你可以这样做:(可能更好,因为我们可能希望机器人改变区域)

class Atlas(object):
    def __init__(self):
        self.robotsToZones = {}

    def add_robot(self, robot, zone='forest')
        self.robotsToZones[robot.name] = zone

    def robotsInWorlds(self):
        return self.robotsToZones.keys()  # .keys() not necessary, but hides representation

(如果您关心速度,您实际上可以两者都做......但您通常不应该关心速度,这需要确保两个结构同步)

此外,您应该只在一个位置存在数据。在您的情况下,Robot 和 Atlas 都需要知道机器人在哪个区域。这很糟糕,因为您必须确保这两个值始终相等且同步,从而导致不必要的头痛和并发症,甚至可能是错误。解决方案是在 robots.py 中忽略机器人所在的区域:

class Robot(object):
    def __init__(self, name):
        self.name = name

机器人永远不需要弄清楚它在哪里;这就是地图集的工作。如果 test.py 需要知道机器人在哪里,它可以做类似的事情myAtlas.whereIs(myRobot),它可以只是return self.robotsToZones[robot.name]. 这称为模块化关注点分离

(旁注:以上假设您有一些其他机制来跟踪哪些机器人在哪些区域中,并且您没有坐标。如果您的step()函数处理坐标,您必须决定是否有全局或每个-区域坐标。后一种情况可能更容易,因为您需要定义的只是区域的边界如何拼接在一起;尽管如果您有 Atlas 定义非重叠(ick,可能的错误)边界,您可以执行第一种情况zone 是哪里。你也可以做一些事情,比如有定义区域边界的路标,机器人在最近的路标区域中。虽然让每个区域由相同大小的矩形组成,可以通过网格表示,但可能是最简单的.)

于 2012-05-24T16:27:34.190 回答
1

您应该将您的机器人添加到Atlas. 而不是self.robot = Robot(robot),添加robots = []Atlas.__init__()self.robots.append(Robot(robot))在中执行Atlas.add_robot(robot)。然后您可以通过列表( 、 等)访问atlas.robots[0].step()它们atlas.robots[1].step()

于 2012-05-24T16:32:12.887 回答
1

您应该能够引用由 中创建的机器人atlasatlas.robot因为那是您存储它的地方。您可以像这样创建一个指向该变量的新变量:

rbt1 = atlas.robot

然后您应该能够按照您的描述引用它:

rbt1.step('left')

请注意,如果您希望atlas能够拥有多个机器人,则应考虑将机器人list存储dictatlas.

于 2012-05-24T16:33:06.523 回答