Brauche Hilfe

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Hautamaeki
User
Beiträge: 3
Registriert: Freitag 12. Juli 2013, 10:27

Hallo,
ich schreibe zurzeit mein erstes Projekt in Python. Ich Programmiere zurzeit Nxt Roboter. Dazu habe ich eine Klasse zum Verbinden zum Nxt Roboter und habe dazu folgenden Code:

Code: Alles auswählen

class ConnectNxt(object):
	def __init__(self):
		self.teamID = -1
		self.teampos = -1
		self.playerID = -1
		self.sock = 0
		self.m_a = 0
		self.m_b = 0
		self.m_c = 0
		self.both = 0
		self.connected = 0
		self.sensor_l = 0
		self.sensor_r = 0
		
	def Connect(self,addr):
		try:
			print "Connecting to NXT"
			self.sock = nxt.bluesock.BlueSock(addr).connect()
			self.m_a = Motor(self.sock, PORT_A)
			self.m_b = Motor(self.sock, PORT_B)
			self.m_c = Motor(self.sock, PORT_C)
			self.sensor_l = Ultrasonic(self.sock, PORT_1)
			self.sensor_r = Ultrasonic(self.sock, PORT_2)
			self.both = nxt.SynchronizedMotors(self.m_b,self.m_c,0)
			self.connected = 1
			print"battery:",self.sock.get_battery_level()
			return 0	#Verbindung erfolgreich
		except:
			print "Connecting failed"
			return 1	#Verbindung fehlgechlagen
	def GetSensor1(self):
		return self.sensor_l.get_sample()
		
	def GetSensor2(self):
		return self.sensor_r.get_sample()				
Es klappt alles bis auf die Sensoren. Wenn ich die Sensorenwerte zurückgeben möchte krieg ich folgede Fehlermeldung
AttributeError: 'int' object has no attribute 'get_sample'
Wie bekomme ich aus dem 'int' object ein 'Ultrasonic' object
Zuletzt geändert von Anonymous am Freitag 12. Juli 2013, 11:01, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
BlackJack

@Hautamaeki: Das kann nur passieren wenn `Ultrasonic()` ein `int` zurück gibt oder Du irgendwo die Attribute an eine ganze Zahl bindest.

Kann es sein, dass Du hier anderen Quelltext zeigst als Du tatsächlich einsetzt? Zum Beispiel welchen wo auch `sensor_l` und `sensor_r` in der `__init__()` an 0 gebunden werden?

Dieser Klassenentwurf mit den ganzen Dummywerten für die Attribute in der `__init__()` ist schlecht. Offensichtlich kann man mit dem Objekt direkt nach dem Erstellen *nichts* anfangen ausser die `Connect()`-Methode aufzurufen. Dann stellt sich aber die Frage warum der Code aus `Connect()` nicht in der `__init__()` steckt‽

Sollte es an dem unsäglichen Fehlerrückgabewert bei `Connect()` liegen, der eigentlich ein Wahrheitswert wäre, wo die Zahlenwerte aber genau entgegen der Intuition gewählt wurden (wir sind hier nicht bei C-Programmierung), ist das kein guter Grund. Ausnahmen wurden erfunden um diese speziellen Fehlerrückgabewerte loszuwerden. Und Du verwendest jetzt Ausnahmebehandlung um genau diesen Mist wieder einzuführen.

Zumal die Ausnahmebehandlung mit dem nackten ``except:`` grundsätzlich keine gute Idee ist. Das verschluckt *alle* Ausnahmen und tut so als wenn die Verbindung nicht zustande gekommen wäre. Auch dann wenn die Verbindung doch zustande kam und/oder das Problem ganz woanders lag. Zum Beispiel eine `NameError` oder `AttributeError` wenn Du Dich irgendwo im ``try``-Block bei einem Namen vertippt hast. Viel Spass bei der Fehlersuche in solchen Fällen. Zu einem ``except`` gehören entweder konkrete Ausnahmen die man erwartet, oder man ``raise``\d die Ausnahme im ``except``-Block, oder man protokolliert sie irgendwo, damit unerwartete Ausnahmen nicht unentdeckt bleiben.

Werte wie -1 und 0 als spezielle „Hier ist noch nichts”-Werte sind ungünstig. Insbesondere wenn sie in der weiteren Verwendung nicht zwingend auffallen. Für „Nichts” gibt es in Python den Wert `None`.

Und wie schon gesagt: Python kennt Wahrheitswerte, da sollte man keine Zahlen zu missbrauchen. Bei `True` und `False` weiss der Leser sofort welcher Wertebereich sehr wahrscheinlich zulässig ist. Bei 0 und 1 könnte man denken es käme auch -1 oder 42 in Frage.

Abkürzungen sollte man vermeiden, solange sie nicht allgemein bekannt sind.

Aus den Gettern könnte man Properties machen. Siehe die `property()`-Funktion.

Zur Namenskonvention und Leerzeichensetzung/Einrückung könntest Du mal einen Blick in den Style Guide for Python Code werfen.

Edit: Ungetestet:

Code: Alles auswählen

class ConnectNxt(object):
    def __init__(self, address):
        self.team_id = None
        self.team_position = None
        self.player_id = None
        LOG.info('Connecting to NXT')
        self.sock = nxt.bluesock.BlueSock(address).connect()
        self.motors = [Motor(self.sock, p) for p in [PORT_A, PORT_B, PORT_C]]
        self.synchronized_motors = nxt.SynchronizedMotors(
            self.motors[1], self.motors[2], 0
        )
        self._left_sensor = Ultrasonic(self.sock, PORT_1)
        self._right_sensor = Ultrasonic(self.sock, PORT_2)
        LOG.info('battery %s', self.battery_level)

    @property
    def battery_level(self):
        return self.sock.get_battery_level()
    
    @property
    def left_sensor(self):
        return self._left_sensor.get_sample()

    @property
    def right_sensor(self):
        return self._right_sensor.get_sample()
`LOG` ist ein modulglobaler Logger aus dem `logging`-Modul. Bei `info()` muss man die Stufe noch entsprechend setzen, damit das ausgegeben wird.
Hautamaeki
User
Beiträge: 3
Registriert: Freitag 12. Juli 2013, 10:27

Erstmal danke für deine Antwort.
Ja ich hab beim erstellen dieses Thema einen falschen quellcode eingefügt.
Sollte heißen

Code: Alles auswählen

sensor_l = 0
sensor_r = 0
Ich hab die Klasse jetzt mal ausgelagert und dann probiert ob es klappt und da klappt es auch. Deswegen bin ich ein bisschen am verzweifeln.
Ich hab auch None schon eingesetzt gehabt dann kommt die Fehlermeldung
AttributeError:'NoneType' object has no attribute 'get_sample'

Edit: Connect steckt nicht in der __init__, weil beim anlgen des objektes noch nicht verbunden werden soll. Außerdem hab ich manche Methoden in diesem Them nicht mit hineingeschrieben da sie nicht so wichtig sind für diesen Fehler
BlackJack

@Hautamaeki: `None` statt 0 behebt ja auch nicht den eigentlichen Fehler, aber das ist auf jeden Fall der bessere Wert für die Initialisierung wenn man sagen will, das hat noch keinen Wert.

Nimm doch mal diese unsinnige Ausnahmebehandlung aus der `Connect()`-Methode heraus. Ich wette Du schiesst Dir damit gerade selbst in den Fuss.

Auch wenn die Klasse noch mehr Funktionalität hat, ist das ein schlechter Entwurf. Wahrscheinlich deswegen *noch* schlechter. Warum soll eine Klasse die dem Namen nach eine Verbindung darstellt, nach dem erstellen nicht verbunden sein? Objekte sollten in der Regel nach der Erstellung benutzbar sein und nicht noch zusätzlich einen Initialisierungsaufruf benötigen.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Hautamaeki hat geschrieben:Außerdem hab ich manche Methoden in diesem Them nicht mit hineingeschrieben da sie nicht so wichtig sind für diesen Fehler
Minimalbeispiele sind ok. Sie sollten dann aber so gewählt sein, dass der relevante Fehler auch in dem Minimalbeispiel auftritt. Wir kennen ja den echten Code nicht und können daher nur über dieses Minimalbeispiel sprechen. Wenn dann Fehlermeldungen oder Tracebacks zu einem ganz anderen Quelltext kommen, dann wird es umso schwerer, dir sinnvoll zu helfen.
Hautamaeki
User
Beiträge: 3
Registriert: Freitag 12. Juli 2013, 10:27

Dann werd ich das Programm ein bisschen Umstrukturieren und deine Tipps danken annehemen. Mal schauen ob es dann klappt :) .
Antworten