2010-08-12 11 views
4

NB Noob alert ...! J'essaie d'utiliser la récursivité dans une méthode de classe Python, mais avec des résultats limités. J'essaie de construire une classe de voiture, avec des attributs très basiques: id, position dans une route à une voie (représentée par un nombre entier), et vitesse. L'une des fonctions que j'ai utilisé pour retourner l'ID voiture se trouve en face de celui-ci - à savoir si nous avons la classe:Utilisation de la récursivité dans les méthodes de classe Python

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

Maintenant, je suis venu avec la méthode de classe suivante (plus de détails ci-dessous le code):

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 

Le plan est de créer des objets de voiture, puis les stocker dans une liste. Chaque fois que la méthode findSuccessorMethod est appelée, cette liste globale de voitures lui est transmise, par ex.

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) 

Cela fonctionne très bien: la fonction de voiture successeur FIND dire que c2 voiture est en face de voiture c1 (position 7 avant la position 4).

Cependant, je veux que la voiture c1 détermine quelle voiture se trouve devant son successeur immédiat - c'est-à-dire quelle voiture se trouve devant la voiture en avant, qui est dans ce cas la voiture c3. Ma pensée était que si je faisais c1_succ.findSuccessorCars (voitures) alors cela devrait fonctionner correctement: faire type (c1_succ) montre qu'il s'agit d'une instance et hasattr montre qu'il a les attributs d'objets anticipés.

Cependant, lorsque j'essaie d'exécuter c1_succ.findSuccessorCars (cars), un entier est renvoyé. Par conséquent, je suis confus - pourquoi cela ne fonctionne pas? Pourquoi ne pouvez-vous pas récursivement exécuter une méthode de classe de cette façon? D'où vient cet entier? NB Gut feel dit que cela a quelque chose à voir avec l'auto-déclaration, et que je vais devoir modifier mon code pour qu'une liste globale de voitures, ainsi qu'une liste globale de leurs positions actuelles, ou une autre méthode de classe, p.ex. findSuccessorsSuccessor (oui, tout à fait conscient de la dénomination crummy!). Cependant, je suis intéressé de comprendre pourquoi cette approche récursive ne fonctionne pas.

MISE À JOUR

Voici le code demandé pour calculer un écart entre les 2 voitures - je l'apprécie est très basique, donc pas trop rire à l'arrière s'il vous plaît.

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

     gap = otherCar.position_x - thisCar.position_x 

     return gap 
+0

Pouvez-vous poster le code pour 'calculateGap'? Ensuite, il devrait être possible de reproduire ce que vous voyez. – mikej

+0

@The MYYN, ce n'est pas une bonne idée; 'sys.maxint + 1' est un entier valide. 'None' fait une meilleure sentinelle. – habnabit

Répondre

2

Votre méthode fonctionne en théorie; c'est un bug d'implémentation. Cela dit, ce n'est pas la bonne façon de faire les choses; spécifiquement, findSuccessorCar ne devrait pas être une méthode de classe de Car. Cela est dû au fait que la liste des instances Car est une construction distincte; la classe Car ne sait pas et ne devrait rien savoir à ce sujet. Si vous voulez faire une classe pour cela, vous devez créer une Road qui est une liste de Cars, et mettre findSuccessorCar sur cela.

Cela dit, je ne vois pas pourquoi vous ne pouvez pas

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

pour trier la liste des voitures afin de position. Je pense que vous implémentez votre propre algorithme de tri pour trouver la voiture de successeur?

Autres points à noter: vous devez utiliser des exceptions (raise BadCarMojoError) pour indiquer un échec, et non des codes de retour magiques; classmethods utilise traditionnellement cls au lieu de self comme premier argument; et Car doit hériter de 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: Voiture séparée de la route. 'Car.successor (self, road)' peut être ajouté pour que le "successeur" original fonctionne, étant donné un objet Road spécifique. –

+0

Je voudrais que 'Car' ait un attribut d'instance' road' qui est défini par 'Road.driveOn' de sorte que vous n'ayez pas besoin de parcourir toutes les instances de' Road' pour trouver celle d'une voiture particulière. – aaronasterling

4

Qu'est-ce que vous appelez une méthode de classe est en fait une méthode d'instance. Les méthodes de classe fonctionnent sur la classe et les méthodes d'instance fonctionnent sur l'instance . Ici, nous traitons des instances Car, pas de la classe Car elle-même.

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) 

Sortie:

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

Je ne comprends toujours pas pourquoi vous implémentez votre propre tri plutôt que d'utiliser Python! – katrielalex

+0

Merci d'avoir fourni l'exemple de code. Cependant, j'ai encore du mal à comprendre: pourquoi votre version fonctionne-t-elle et la mienne non? –

Questions connexes