0

test.py というファイルを使用して 2 つのクラスをテストしています。私はプログラミングを学んでいるので、これは単なる練習プログラムです。1 つのアトラス (マップ) があり、1 つのマップ内に複数の「ロボット」を配置できます。

#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 でキーワードを使用して意図を宣言する必要があります。これを行う

この問題が発生しないように制御フローを変更するには、完全に作成されたロボットを渡すことで 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

(速度を気にするなら、実際には両方を行うことができます...しかし、通常は速度を気にするべきではなく、両方の構造が同期していることを確認する必要があります)

また、データは 1 つの場所に存在する必要があります。あなたの場合、Robot と Atlas の両方が、ロボットがどのゾーンにいるかを知る必要があります。これは、これら 2 つの値が常に等しく、同期していることを確認する必要があるため、不必要な頭痛や複雑さ、さらにはバグにつながるため、悪いことです。解決策は、robot.py でロボットがどのゾーンにいるかを無視することです。

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

ロボットは自分がどこにいるかを把握する必要はありません。それがアトラスの仕事です。test.py がロボットの場所を知る必要がある場合、 のようなことを実行myAtlas.whereIs(myRobot)できますreturn self.robotsToZones[robot.name]。これは、関心のモジュール化および分離として知られています。

(補足:上記は、どのロボットがどのゾーンにいるかを追跡するための他のメカニズムがあり、座標がないことを前提としています。step()関数に座標を処理させる場合は、グローバルまたはパーのどちらを使用するかを決定する必要があります。 -ゾーンの座標. 定義する必要があるのはゾーンの境界をどのようにつなぎ合わせるかだけなので、後者のケースはおそらく簡単です; ただし、アトラスに重複しない (バグの可能性がある) 境界を定義させれば、最初のケースを行うことができます。ゾーンはどこにあります. ゾーンの境界を定義する道しるべを持ち、ロボットが最も近い道しるべのゾーンにいるようなこともできるかもしれません. ただし、各ゾーンを同じサイズの長方形で作成し、グリッドを介して表現できるようにするのがおそらく最も簡単です. .)

于 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

atlasによって作成されたロボットを参照できるはずです。これは、ロボットatlas.robotを保存した場所だからです。次のように、それを指す新しい変数を作成できます。

rbt1 = atlas.robot

次に、説明したようにそれを参照できるはずです。

rbt1.step('left')

atlas複数のロボットを使用できるようにする場合は、ロボットを内のlistまたはdictオブジェクトに格納することを検討する必要があることに注意してくださいatlas

于 2012-05-24T16:33:06.523 に答える