4 Stimmen

Rekursion in Python-Klassenmethoden verwenden

NB Noob-Alarm ... !

Ich versuche, die Rekursion in einer Python-Klassen-Methode zu verwenden, aber mit begrenzten Ergebnissen.

Ich versuche, eine Auto-Klasse zu bauen, mit sehr grundlegenden Attribute: id, Position in einer einspurigen Straße (dargestellt durch eine ganze Zahl), und Geschwindigkeit. Eine der Funktionen, die ich habe, wird verwendet, um zurückzugeben, welches Auto id ist vor auf dieser - d.h., wenn wir Klasse haben:

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

Nun habe ich mir die folgende Klassenmethode ausgedacht (weitere Details unterhalb des Codes):

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

Der Plan ist, Auto-Objekte zu erstellen und sie dann in einer Liste zu speichern. Jedes Mal, wenn die findSuccessorMethode aufgerufen wird, wird diese globale Liste von Autos an sie übergeben, z.B.

    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)

Das funktioniert gut: Die Funktion find successor car sagt, dass der Wagen c2 vor dem Wagen c1 steht (Position 7 vor Position 4).

Ich möchte jedoch, dass Auto c1 herausfindet, welches Auto vor seinem unmittelbaren Nachfolger steht - das heißt, welches Auto vor dem Auto davor steht, das in diesem Fall Auto c3 ist. Mein Gedanke war, dass, wenn ich c1_succ.findSuccessorCars(cars) dann sollte dies gut funktionieren: tun type(c1_succ) zeigt es ist eine Instanz und hasattr zeigt, dass es die erwarteten Objektattribute hat.

Wenn ich jedoch versuche, c1_succ.findSuccessorCars(cars) auszuführen, wird eine Ganzzahl zurückgegeben. Daher bin ich verwirrt - warum funktioniert das nicht? Warum kann man eine Klassenmethode nicht auf diese Weise rekursiv ausführen? Woher kommt diese ganze Zahl?

NB Das Bauchgefühl sagt, dass dies etwas mit der Selbstdeklaration zu tun hat, und dass ich meinen Code so ändern muss, dass es neben einer globalen Liste der Autos auch eine globale Liste ihrer aktuellen Positionen geben muss, oder eine andere Klassenmethode, z. B. findSuccessorsSuccessor (ja, ich bin mir der miserablen Namensgebung voll bewusst!) Ich bin jedoch daran interessiert zu verstehen, warum dieser rekursive Ansatz nicht funktioniert.

UPDATE

Hier ist der angeforderte Code für die Berechnung eines Abstands zwischen 2 Autos - ich weiß, dass es sehr einfach ist, also bitte nicht zu viel Gelächter auf der Rückseite.

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

        gap = otherCar.position_x - thisCar.position_x 

        return gap

5voto

habnabit Punkte 9240

Was Sie eine Klassenmethode nennen, ist eigentlich eine Instanzmethode. Klassenmethoden arbeiten mit der Klasse und Instanzmethoden wirken auf die Instanz . Hier haben wir es mit Car-Instanzen zu tun, nicht mit der Klasse Car selbst.

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)

Ausgabe:

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

2voto

Katriel Punkte 115208

Ihre Methode funktioniert in der Theorie; dies ist ein Implementierungsfehler. Das heißt, es ist nicht der richtige Weg, die Dinge zu tun; insbesondere, findSuccessorCar sollte nicht eine Klassenmethode von Car . Dies liegt daran, dass die Liste der Car Instanzen ist ein eigenes Konstrukt; die Klasse Car nichts davon weiß und nichts davon wissen sollte. Wenn Sie eine Klasse dafür erstellen wollten, sollten Sie eine Road die eine Liste von Cars und setzen findSuccessorCar dazu.

Dennoch sehe ich keinen Grund, warum Sie nicht auch

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

um die Liste der Fahrzeuge in der Reihenfolge der Positionen zu sortieren. Ich denke, Sie implementieren Ihren eigenen Sortieralgorithmus, um das Nachfolgefahrzeug zu finden?

Weitere wichtige Punkte: Sie sollten Ausnahmen verwenden ( raise BadCarMojoError ), um ein Scheitern anzuzeigen, keine magischen Rückgabewerte; classmethods verwenden traditionell cls 代わりに self als erstes Argument; und Car sollte erben von 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 )

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X