简体   繁体   English

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

[英]Python Class - why do I have to set my class variable equal to itself when setting instance variable

I am working through Udacity's Artificial Intelligence course for Robotics and came across something puzzling.我正在学习 Udacity 的机器人人工智能课程,遇到了一些令人费解的事情。 The course has written a robot class for us to use (I take no credit for this code).该课程编写了一个机器人 class 供我们使用(我不相信这段代码)。

There is a set method which is used to set the x,y & orientation of the robot which are parameters within the class.有一种set方法用于设置机器人的 x、y 和方向,它们是 class 中的参数。 The robot is initialized at (30,50,pi/2) in the 2D world and after two movements of (-pi/2, 15) and (-pi/2, 10) the sense function should estimate ~ [32.0156, 53.1507, 47.1699, 40.3112] as the distance to the landmarks.机器人在 2D 世界中初始化为(30,50,pi/2) ,经过(-pi/2, 15)(-pi/2, 10)两次运动后,感觉 function 应该估计 ~ [32.0156, 53.1507, 47.1699, 40.3112]作为到地标的距离。 In the driver code at the bottom, I'm finding my answers differ depending on whether I set the class instance equal to itself after the .set() method.在底部的驱动程序代码中,我发现我的答案有所不同,具体取决于我在.set()方法之后是否将 class 实例设置为等于自身。 And I can't figure out why this would matter.我不明白为什么这很重要。 I figured the .set() method would update that instance of the class's variables.我认为.set()方法会更新该类变量的实例。 Without the equal signs I get a sense estimate of [31.6227, 58.3095, 31.6227, 58.3095] .没有等号,我得到[31.6227, 58.3095, 31.6227, 58.3095]的感觉估计。

The driver code I'm talking about is:我正在谈论的驱动程序代码是:

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())

VS...对...

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

ROBOT CLASS:机器人 CLASS:

# 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())
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())

In the above code, you are doing correct as per the question asked that is, setting the robot at (30,50, pi/2) and sense after one move and again sense after second move.在上面的代码中,您按照所提出的问题做的是正确的,即将机器人设置为 (30,50, pi/2) 并在一次移动后感知并在第二次移动后再次感知。

Since move method is returning a new instance that is now moved from its original position(ie at [30,50,pi/2]) or you can say that in move method position of myrobot object is not set but the programmer is setting position of new instance (ie res).由于move方法正在返回一个现在从其原始位置移动的新实例(即在 [30,50,pi/2] 处) ,或者您可以说在 myrobot object 的move方法 position 中没有设置,但程序员正在设置 Z4757FE07FD492ADBBE60EAZ6新实例(即 res)。 So the position of myrobot that you declared will remain same, so to avoid this, you need to re-instantiate with the object returned by the move method.因此,您声明的 myrobot 的 position 将保持不变,因此为避免这种情况,您需要使用move方法返回的 object 重新实例化。

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())

However, in the 2.) code, you will get the same result of sense even after you moved the robot two times.但是,在 2.) 代码中,即使移动机器人两次,您也会得到相同的感知结果。 The result of the above two print instruction in 2.) code will be same as when you set the robot at (30,50, pi/2) and it is remained same, because in move method, new instance is being created and position of this new instance is being changed. 2.) 代码中上述两条打印指令的结果将与您将机器人设置为 (30,50, pi/2) 时相同,并且保持不变,因为在move方法中,正在创建新实例和 position正在更改此新实例。

Since the attributes you are changing is not the class attributes(ie x,y and orientation are not common to every object).由于您要更改的属性不是 class 属性(即 x、y 和方向并非每个对象都通用)。 That is why, by changing attributes for one object will not change the corresponding attributes of other object.这就是为什么通过更改一个 object 的属性不会更改其他 object 的相应属性。 since every instance of a class has their own copy of attributes and methods.因为 class 的每个实例都有自己的属性和方法副本。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM