Python类-为什么在设置实例变量时必须将类变量设置为等于自身

Python类-为什么在设置实例变量时必须将类变量设置为等于自身,python,python-3.x,class,oop,instance-variables,Python,Python 3.x,Class,Oop,Instance Variables,我正在学习Udacity的机器人人工智能课程,遇到了一些令人费解的事情。这门课程已经为我们编写了一个机器人类(我对这段代码没有学分) 有一个set方法,用于设置机器人的x、y和方向,这些都是类中的参数。机器人在2D世界中初始化为(30,50,pi/2),在(-pi/2,15)和(-pi/2,10)两次移动后,感知功能应估计[32.0156,53.1507,47.1699,40.3112]到地标的距离。在底部的驱动程序代码中,我发现我的答案有所不同,这取决于我是否在.set()方法之后将类实例设置

我正在学习Udacity的机器人人工智能课程,遇到了一些令人费解的事情。这门课程已经为我们编写了一个机器人类(我对这段代码没有学分)


有一个
set
方法,用于设置机器人的x、y和方向,这些都是类中的参数。机器人在2D世界中初始化为
(30,50,pi/2)
,在
(-pi/2,15)
(-pi/2,10)
两次移动后,感知功能应估计[32.0156,53.1507,47.1699,40.3112]到地标的距离。在底部的驱动程序代码中,我发现我的答案有所不同,这取决于我是否在
.set()
方法之后将类实例设置为等于自身。我不明白为什么这很重要。我认为
.set()
方法将更新该类变量的实例。如果没有等号,我得到的感觉估计值是
[31.6227,58.3095,31.6227,58.3095]

我说的驱动程序代码是:

myrobot = robot()
myrobot.set(30, 50, pi/2)
myrobot = myrobot.move(-(pi/2), 15)
print(myrobot.sense())
myrobot = myrobot.move(-(pi/2), 10)
print(myrobot.sense())

机器人等级:

# Make a robot called myrobot that starts at
# coordinates 30, 50 heading north (pi/2).
# Have your robot turn clockwise by pi/2, move
# 15 m, and sense. Then have it turn clockwise
# by pi/2 again, move 10 m, and sense again.
#
# Your program should print out the result of
# your two sense measurements.
#
# Don't modify the code below. Please enter
# your code at the bottom.

from math import *
import random



landmarks  = [[20.0, 20.0], [80.0, 80.0], [20.0, 80.0], [80.0, 20.0]]
world_size = 100.0


class robot:
    def __init__(self):
        self.x = random.random() * world_size
        self.y = random.random() * world_size
        self.orientation = random.random() * 2.0 * pi
        self.forward_noise = 0.0;
        self.turn_noise    = 0.0;
        self.sense_noise   = 0.0;

    def set(self, new_x, new_y, new_orientation):
        if new_x < 0 or new_x >= world_size:
            raise (ValueError, 'X coordinate out of bound')
        if new_y < 0 or new_y >= world_size:
            raise (ValueError, 'Y coordinate out of bound')
        if new_orientation < 0 or new_orientation >= 2 * pi:
            raise (ValueError, 'Orientation must be in [0..2pi]')
        self.x = float(new_x)
        self.y = float(new_y)
        self.orientation = float(new_orientation)


    def set_noise(self, new_f_noise, new_t_noise, new_s_noise):
        # makes it possible to change the noise parameters
        # this is often useful in particle filters
        self.forward_noise = float(new_f_noise);
        self.turn_noise    = float(new_t_noise);
        self.sense_noise   = float(new_s_noise);


    def sense(self):
        Z = []
        for i in range(len(landmarks)):
            dist = sqrt((self.x - landmarks[i][0]) ** 2 + (self.y - landmarks[i][1]) ** 2)
            dist += random.gauss(0.0, self.sense_noise)
            Z.append(dist)
        return Z


    def move(self, turn, forward):
        if forward < 0:
            raise (ValueError, 'Robot cant move backwards')         

        # turn, and add randomness to the turning command
        orientation = self.orientation + float(turn) + random.gauss(0.0, self.turn_noise)
        orientation %= 2 * pi

        # move, and add randomness to the motion command
        dist = float(forward) + random.gauss(0.0, self.forward_noise)
        x = self.x + (cos(orientation) * dist)
        y = self.y + (sin(orientation) * dist)
        x %= world_size    # cyclic truncate
        y %= world_size

        # set particle
        res = robot()
        res.set(x, y, orientation)
        res.set_noise(self.forward_noise, self.turn_noise, self.sense_noise)
        return res

    def Gaussian(self, mu, sigma, x):

        # calculates the probability of x for 1-dim Gaussian with mean mu and var. sigma
        return exp(- ((mu - x) ** 2) / (sigma ** 2) / 2.0) / sqrt(2.0 * pi * (sigma ** 2))


    def measurement_prob(self, measurement):

        # calculates how likely a measurement should be

        prob = 1.0;
        for i in range(len(landmarks)):
            dist = sqrt((self.x - landmarks[i][0]) ** 2 + (self.y - landmarks[i][1]) ** 2)
            prob *= self.Gaussian(dist, self.sense_noise, measurement[i])
        return prob



    def __repr__(self):
        return '[x=%.6s y=%.6s orient=%.6s]' % (str(self.x), str(self.y), str(self.orientation))



def eval(r, p):
    sum = 0.0;
    for i in range(len(p)): # calculate mean error
        dx = (p[i].x - r.x + (world_size/2.0)) % world_size - (world_size/2.0)
        dy = (p[i].y - r.y + (world_size/2.0)) % world_size - (world_size/2.0)
        err = sqrt(dx * dx + dy * dy)
        sum += err
    return sum / float(len(p))



####   DON'T MODIFY ANYTHING ABOVE HERE! ENTER CODE BELOW ####

myrobot = robot()
myrobot.set(30, 50, pi/2)
myrobot = myrobot.move(-(pi/2), 15)
print(myrobot.sense())
myrobot = myrobot.move(-(pi/2), 10)
print(myrobot.sense())
#制作一个名为myrobot的机器人,从
#坐标30,50向北(pi/2)。
#让你的机器人顺时针旋转pi/2,移动
#15米,还有感觉。然后让它顺时针转动
#再次按pi/2,移动10米,然后再次感知。
#
#你的程序应该打印出测试结果
#你的两个感官测量。
#
#不要修改下面的代码。请输入
#你的代码在底部。
从数学导入*
随机输入
地标=[[20.0,20.0],[80.0,80.0],[20.0,80.0],[80.0,20.0]]
世界面积=100.0
职业机器人:
定义初始化(自):
self.x=random.random()*世界大小
self.y=random.random()*世界大小
self.orientation=random.random()*2.0*pi
自前向_噪声=0.0;
自转噪声=0.0;
自感应噪声=0.0;
def设置(自我、新x、新y、新方向):
如果新尺寸<0或新尺寸>=世界尺寸:
raise(ValueError,“X坐标超出范围”)
如果新建y<0或新建y>=世界大小:
raise(ValueError,“Y坐标超出范围”)
如果新方向<0或新方向>=2*pi:
raise(ValueError,'方向必须在[0..2pi]')
self.x=浮动(新的)
self.y=浮动(新的)
self.orientation=浮动(新的_方向)
def设置_噪波(自身、新_f_噪波、新_t_噪波、新_s_噪波):
#使更改噪波参数成为可能
#这在粒子过滤器中通常很有用
self.forward\u noise=浮动(新的\u\u noise);
self.turn\u noise=浮动(新的\u\u noise);
self.sense\u noise=浮动(新的\u噪声);
def感应(自我):
Z=[]
对于范围内的i(len(地标)):
dist=sqrt((self.x-landmarks[i][0])**2+(self.y-landmarks[i][1])**2)
距离+=随机高斯(0.0,自感知噪声)
Z.append(dist)
返回Z
def移动(自身、转弯、前进):
如果向前<0:
升起(值错误,“机器人无法向后移动”)
#“旋转”,并向“旋转”命令添加随机性
方向=自定向+浮动(旋转)+随机高斯(0.0,自旋转噪声)
方向%=2*pi
#移动,并向“运动”命令添加随机性
dist=浮点(正向)+随机高斯(0.0,自前向噪声)
x=自身x+(cos(方向)*距离)
y=自身y+(正弦(方向)*距离)
x%=世界#U大小#循环截断
y%=世界尺寸
#固定粒子
res=机器人()
分辨率设置(x、y、方向)
res.set\U噪声(自前向噪声、自转弯噪声、自感知噪声)
返回res
def高斯(自、μ、σ、x):
#计算具有平均μ和var.sigma的一维高斯的x概率
返回exp(-(μ-x)**2)/(σ**2)/2.0)/sqrt(2.0*pi*(σ**2))
def测量探头(自身,测量):
#计算度量值应具有的可能性
prob=1.0;
对于范围内的i(len(地标)):
dist=sqrt((self.x-landmarks[i][0])**2+(self.y-landmarks[i][1])**2)
prob*=自高斯(距离、自感知噪声、测量[i])
返回问题
定义报告(自我):
返回“[x=%.6s y=%.6s ORTIONE=%.6s]%”(str(self.x)、str(self.y)、str(self.orientation))
def eval(右、右、右):
总和=0.0;
对于范围内的i(len(p)):#计算平均误差
dx=(p[i].x-r.x+(world_size/2.0))%world_size-(world_size/2.0)
dy=(p[i].y-r.y+(world_size/2.0))%world_size-(world_size/2.0)
err=sqrt(dx*dx+dy*dy)
总和+=错误
返回和/浮动(len(p))
####不要修改上面的任何内容!在下面输入代码####
myrobot=robot()
myrobot.set(30,50,pi/2)
myrobot=myrobot.move(-(pi/2),15)
打印(myrobot.sense())
myrobot=myrobot.move(-(pi/2),10)
打印(myrobot.sense())
在上面的代码中,您按照所问的问题进行了正确的操作,即将机器人设置为(30,50,pi/2),并在一次移动后进行感知,在第二次移动后再次进行感知

由于move方法返回一个新实例,该实例现在从其原始位置(即[30,50,pi/2])移动,可以说在move方法中未设置myrobot对象的位置,但程序员正在设置新实例的位置(即res)。 因此,您声明的myrobot的位置将保持不变,因此为了避免这种情况,您需要使用move方法返回的对象重新实例化

2.) myrobot = robot()
    myrobot.set(30, 50, pi/2)
    myrobot.move(-(pi/2), 15)
    print(myrobot.sense())
    myrobot.move(-(pi/2), 10)
    print(myrobot.sense())
但是,在2.)代码中,即使移动机器人两次,您也会得到相同的感知结果。 2.)代码中上述两条打印指令的结果将与您将机器人设置为(30,50,pi/2)时的结果相同,并且
1.) myrobot = robot()
    myrobot.set(30, 50, pi/2)
    myrobot = myrobot.move(-(pi/2), 15)
    print(myrobot.sense())
    myrobot = myrobot.move(-(pi/2), 10)
    print(myrobot.sense())
2.) myrobot = robot()
    myrobot.set(30, 50, pi/2)
    myrobot.move(-(pi/2), 15)
    print(myrobot.sense())
    myrobot.move(-(pi/2), 10)
    print(myrobot.sense())