2010-08-12 70 views
4

NB Noob警報...!在Python類方法中使用遞歸

我想在Python類方法中使用遞歸,但效果有限。

我試圖建立一個汽車類,具有非常基本的屬性:id,在單車道道路(用整數表示)中的位置和速度。有一個問題我必須用於返回哪輛車ID在前面就這一個功能 - 即,如果我們有類:

class Car: 
    def __init__(self, position, id, velocity): 
     self.position = position 
     self.id = id 
     self.velocity = velocity 

現在,我已經想出了下面的類方法(更多詳細信息如下代碼):

def findSuccessorCar(self, cars): 

    successorCar = "" 
    smallestGapFound = 20000000 

    for car in cars: 
     if car.id == self.id: continue 

     currentGap = self.calculateGap(car) 

     if (currentGap > -1) and (currentGap < smallestGapFound): 
      smallestGapFound = currentGap 
      successorCar = car 

    if successorCar == "": 
     return 1 # calling code checks for 1 as an error code 
    else:   
     return successorCar 

該計劃是創建汽車對象,然後將它們存儲在一個列表中。每次調用findSuccessorMethod時,將這個全局汽車列表傳遞給它,例如,

c1 = testCar.Car(4, 5, 1) # position, pos_y, Vel, ID 
     c2 = testCar.Car(7, 9, 2) 
     c3 = testCar.Car(9, 1, 2) 
     cars = [c1, c2, c3] 

     c1_succ = c1.findSuccessorCar(cars) 

也能正常工作:在找到繼任者車功能會說,汽車C2是在汽車C1(位置7領先的位置4)的前面。

但是,我想讓汽車c1知道哪輛車在它的直接接班人面前 - 也就是說,哪輛汽車在前面的汽車前面,在這種情況下是汽車c3。我的想法是,如果我做了c1_succ.findSuccessorCars(汽車),那麼這應該工作得很好:做type(c1_succ)顯示它是一個實例,hasattr顯示它具有預期的對象屬性。

但是,當我嘗試執行c1_succ.findSuccessorCars(cars)時,返回一個整數。因此,我很困惑 - 爲什麼這不起作用?爲什麼你不能以這種方式遞歸執行一個類方法?這個整數來自哪裏?

NB Gut覺得這與自我聲明有關,而且我需要修改我的代碼,以至於全球汽車列表也需要全局列表他們的當前位置,或另一個類的方法,例如 findSuccessorsSuccessor(是的,完全意識到蹩腳的命名!)。但是,我有興趣瞭解爲什麼這種遞歸方法不起作用。

UPDATE

這裏是計算2臺車之間的間隙的請求的代碼 - 我在後面欣賞它是非常基本的,所以沒有太多的笑聲吧。

def calculateGap(self, car): 
     ''' Calculate the gap between two cars 
     ''' 
     thisCar = self 
     otherCar = car 

     gap = otherCar.position_x - thisCar.position_x 

     return gap 
+0

你能張貼'calculateGap'的代碼?那麼它應該有可能重現你所看到的。 – mikej 2010-08-12 09:11:45

+0

@ MYYN,這不是一個好主意; 'sys.maxint + 1'是一個有效的整數。 「沒有」會成爲更好的哨兵。 – habnabit 2010-08-12 09:20:00

回答

2

你的方法確實在理論上有效;這是一個執行錯誤。這就是說,這不是正確的做事方式;具體而言,findSuccessorCar不應該是Car的分類方法。這是因爲Car實例的列表是一個單獨的構造;類Car不知道,也不應該知道任何事情。如果你想爲它做一個課程,你應該製作一個Road這是一個列表Cars,並把findSuccessorCar就此。

這麼說,我不明白爲什麼你不能這樣做

import operator 
cars.sort(key = operator.attrgetter("position")) 

排序汽車的位置順序列表。我認爲你正在實施自己的排序算法來尋找繼任車?

其他值得注意的地方:你應該使用異常(raise BadCarMojoError)來表示失敗,而不是神奇的返回碼; classmethods傳統上使用cls而不是self作爲第一個參數; Car應該從object繼承。


import bisect 

class Car(object) : 
    def __init__(self, position, id, velocity): 
     self.position = position 
     self.id = id 
     self.velocity = velocity 

    def __lt__(self, other): 
     return self.position < other.position 

class Road(object): 
    def __init__(self): 
     self.cars = [ ] 

    def driveOn(self, car): 
     bisect.insort(self.cars, car) 

    def successor(self, car): 
     i = bisect.bisect_left(self.cars, car) 
     if i == len(self.cars): 
      raise ValueError('No item found with key at or above: %r' % (car,)) 
     return self.cars[ i + 1 ] 

c1 = Car(4, 5, 1) 
c2 = Car(7, 9, 2) 
c3 = Car(9, 1, 2) 
c1 < c2 

road = Road() 

for car in (c1, c2, c3): 
    road.driveOn(car) 

c1_succ = road.successor(c1) 
+0

+1:從道路上分離的汽車。 'Car.successor(self,road)'可以被添加,以便原來的「繼承者」在給定一個特定的道路對象的情況下工作。 – 2010-08-12 10:26:28

+0

我想'Car'有'Road.driveOn'設置的'road'實例屬性,這樣你就不必通過'Road'的每一個實例去找出某個特定的汽車在哪個位置。 – aaronasterling 2010-08-12 10:52:53

4

你調用什麼類方法實際上是一個實例方法。類方法在上操作,並且實例方法在實例上操作。在這裏,我們正在處理Car實例,而不是Car類本身。

class Car(object): 
    def __init__(self, position, id, velocity): 
     self.position = position 
     self.id = id 
     self.velocity = velocity 

    def __eq__(self, other): 
     return self.id == other.id 

    def __str__(self): 
     return 'Car(%d, %d, %d)' % (self.position, self.id, self.velocity) 

    def calculateGap(self, other): 
     return other.position - self.position 

    def findSuccessor(self, cars): 
     ret = smallestGap = None 
     for car in cars: 
      if car == self: 
       continue 
      gap = self.calculateGap(car) 
      if gap < 0: 
       continue 
      if smallestGap is None or gap < smallestGap: 
       ret, smallestGap = car, gap 
     return ret 

    def findNthSuccessor(self, n, cars): 
     cur = self 
     for x in xrange(n): 
      cur = cur.findSuccessor(cars) 
      if cur is None: 
       return None 
     return cur 

c1 = Car(4, 5, 1) 
c2 = Car(7, 9, 2) 
c3 = Car(9, 1, 2) 
cars = [c1, c2, c3] 

print c1.findSuccessor(cars) 
print c1.findSuccessor(cars).findSuccessor(cars) 
print c1.findNthSuccessor(2, cars) 

輸出:

Car(7, 9, 2) 
Car(9, 1, 2) 
Car(9, 1, 2) 
+1

我還是不明白你爲什麼要實現自己的排序而不是使用Python的! – katrielalex 2010-08-12 09:35:17

+0

感謝您提供代碼示例。然而,我仍然在努力理解:爲什麼你的版本工作,我的不工作? – 2010-08-13 15:41:08