如何引用在不同对象中创建的对象

时间:2012-05-24 16:24:27

标签: python

我正在使用名为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')”之类的命令来控制机器人。

3 个答案:

答案 0 :(得分:3)

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

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

  • 通过更改控制流来重构您的代码,因此您没有遇到此问题(如下面的演示)
  • 传入参数/访问者 - 请求对象为您提供与您所知道的相匹配的机器人(在本例中为名称)
  • 浅层数据结构 - Atlas将是一个浅壳,其行为类似于字典,您只需将其视为字典(与下面的yourAtlas.robotsToZones(...)相反)
  • 滥用全局变量 - 从不这样做,这是一个糟糕的编程
  • 闭包 - 如果你在一个函数内部定义一个函数(甚至可能是一个类中的一个类,但是它变得丑陋),内部函数可以访问外部函数中的变量,尽管你必须使用nonlocal python中的关键字声明你打算这样做

要更改控制流程,以免出现此问题:通过传入一个完整的机器人,可以使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.py中忽略机器人所在的区域:

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

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

(旁注:以上假设你有一些其他的机制来跟踪哪些机器人在哪些区域,你没有坐标。如果你有step()函数处理坐标,你将有判断你是否有全局或每区域坐标。后一种情况可能更容易,因为您需要定义的是区域边界如何拼接在一起;尽管如果你有Atlas定义非重叠,你可以做第一种情况( ick,可能的错误)区域在哪里。你也可以做一些像路标定义区域边界的东西,机器人在最近的路标区域。尽管每个区域由同样大小的矩形组成,通过网格表示,可能是最简单的。)

答案 1 :(得分: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()等)访问它们。

答案 2 :(得分:1)

您应该可以通过atlas引用在atlas.robot内创建的机器人,因为这是您存储它的地方。你可以像这样创建一个指向它的新变量:

rbt1 = atlas.robot

然后你应该能够像你描述的那样引用它:

rbt1.step('left')

请注意,如果您希望atlas能够拥有多个漫游器,则应考虑将机器人存储在list内的dictatlas对象中。