您应该在 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 是哪里。你也可以做一些事情,比如有定义区域边界的路标,机器人在最近的路标区域中。虽然让每个区域由相同大小的矩形组成,可以通过网格表示,但可能是最简单的.)