Liste wird nicht vollständig ausgegeben

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
carstenAC
User
Beiträge: 4
Registriert: Mittwoch 7. September 2016, 08:20

Hallo zusammen,

ich bin ziemlich neu in Python und im programmieren. Bis jetzt konnte ich mir mit Literatur und google ziemlich weiterhelfen, hänge aber jetzt an einem Problem.
Ich habe eine Funktion, in der eine Liste erstellt wird und mit return ausgegeben wird.

Code: Alles auswählen

def getPosition(liste,seitenabstand,randabstand):
    
    for wert in [liste]:
         Anzahl=liste[0] 
         Abstand=liste[1]
         
    for x in range(Anzahl):             
         x=seitenabstand+(x*Abstand)
         return [x,randabstand]
Wenn ich die Liste in einer anderen Funktion verwenden will, habe ich nur die erste Stelle der Liste. Wenn ich return durch print ersetze zeigt er mir die komplette Liste an, aber ich kann nicht mit den Werten arbeiten.
Wie bekomme ich die Werte der ersten Funktion in die zweite Funktion?

VG
carsten
Zuletzt geändert von Anonymous am Mittwoch 7. September 2016, 09:02, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

@carstenAC: versuch zuerst einmal mit Worten zu beschreiben, was Du tun willst und was das Programm tatsächlich macht. Gehe dazu Schritt für Schritt die for-Schleifen durch. Was passiert z.B. in der ersten for-Schleife im ersten Durchgang, gibt es einen zweiten Durchgang und was passiert dort? Bei der zweiten for-Schleife gibt es nämlich nur einen Durchgang, weil mit dem return die Funktion sofort verlassen wird.
BlackJack

@carstenAC: ``return`` beendet die Abarbeitung der Funktion und gibt das Ergebnis an den Aufrufer zurück, welches nach dem ``return`` angegeben ist. Du gibst da also im ersten Schleifendurchlauf eine Liste mit zwei Elementen zurück. Das ist das vollständige Ergebnis der Funktion so wie Du sie geschrieben hast.

Jetzt ist also die Frage was Du *eigentlich* zurückgeben wolltest‽ Da kann man jetzt nur raten, darum sollte man so etwas bei Fragestellungen mit dazu schreiben. Also nicht nur das die Funktion nicht das liefert was sie soll, sondern auch wie das Wunschergebnis aussehen sollte.

Weitere Anmerkungen: Die erste Schleife ist sinnlos. Du steckst da *einen* Wert in eine Liste und iterierst dann über diese Liste von der genau bekannt ist, das sie nur einen Wert enthält. Das macht überhaupt keinen Sinn, weil die Schleife dann ganz genau *einmal* durchlaufen wird, also das was im Schleifenkörper gemacht wird, passiert genau *einmal*. Das kann man also einfacher ohne die Schleife ausdrücken. Schleifen sind dazu da Code wiederholt auszuführen. `wert` wird innerhalb der Schleife ja auch gar nicht verwendet — der Name ist ja auch an den selben Wert wie der Name `liste` gebunden.

`liste` ist kein guter Name falls es sich nicht um eine generische Funktion handelt bei der im Grunde egal ist was die Werte in der Liste bedeuten. Das ist hier offensichtlich nicht der Fall. Namen sollen dem Leser vermitteln was der Wert, der dahinter steckt, im Kontext des Programms bedeutet. Da der nicht weiter bekannt ist, habe ich jetzt zum Beispiel Schwierigkeiten zu raten was denn ein besserer Name währe und damit verstehe ich den Sinn der Funktion auch nicht.

An der Stelle würde ich auch überlegen ob man eine Liste übergeben will statt einfach der beiden Werte, für die es ja schon passende Namen gibt. Insbesondere wenn es Schwierigkeiten bereiten sollte einen passenden Namen für `liste` zu finden, hat man an der Stelle vielleicht etwas zu einer Datenstruktur zusammengefasst, was nicht unbedingt zusammen gehört.

Ein bisschen was zu Konventionen:

Einrücken immer mit vier Leerzeichen pro Ebene. Die Schleifenkörper sind ein Leerzeichen zu tief eingerückt.

Namen für alles ausser Klassen und Konstanten schreibt man klein und mit Unterstrichen. Also `get_position()` statt `getPosition()` und `anzahl` statt `Anzahl`.

Vor und nach binären Operatoren und dem ``=`` bei Zuweisungen, sowie nach Kommas erhöht ein Leerzeichen die Lesbarkeit. Syntaxhervorhebung hilft da ein bisschen, aber ohne sieht so etwas zusammengequetschtes schnell unübersichtlich aus.

Ich lande dann bei dieser Funktion:

Code: Alles auswählen

def get_position(anzahl, abstand, seitenabstand, randabstand):
   
    for x in range(anzahl):            
        return [seitenabstand + (x * abstand), randabstand]
Die allerdings noch das gleiche Problem hat, aber da müsstest Du erst einmal beschrieben wie das tatsächliche Ergebnis denn nun aussehen soll. Ich habe aber schon den Verdacht, das der Funktionsname unpassend ist, weil da mehr als eine Position ermittelt wird.
carstenAC
User
Beiträge: 4
Registriert: Mittwoch 7. September 2016, 08:20

Hallo Sirius3,
der Sinn der Funktion ist, mir für eine Anzahl Markierungen den x- und y- Wert auszugeben.

Die Funktion bekommt 3 Wert,

Code: Alles auswählen

def getPosition(Liste=(5,490),20,100):
der erste Wert (die 5) bedeutet, das es 5 Markierungen sein sollen. Der zweite Wert bedeutet, dass die Markierungen 490 mm Abstand zueinander haben. Der dritte und vierte Wert bedeuten den Abstand der Markierungen zum Rand der Markierung.

in der liste sind zwei Werte (Anzahl=liste[0] ,Abstand=liste[1])
Daraus errechne ich die x-Position.
Die Funktion soll mir dann in diesem Fall 5 x-und y-Werte ausgeben.
Markierung 1=20,100
Markierung 2=510, 100
Markierung 3=100, 100
und so weiter...
Er gibt mir aber nur die 20,100 aus.
Hoffe das ist einigermaßen klar.
BlackJack

@carstenAC: Wenn Du mehr als eine Position zurückgeben willst, dann musst Du Dir erst eine Datenstruktur mit den Positionen erstellen. Zum Beispiel eine Liste mit den Positionen. Und die dann am Ende zurückgeben.

Die Funktion sollte dann auch in der Mehrzahl bennannt werden: `get_positions()`.

Und Du könntest Dir mal die Syntax für „list comprehensions“ anschauen, die passt hier nämlich sehr gut zum Problem.
carstenAC
User
Beiträge: 4
Registriert: Mittwoch 7. September 2016, 08:20

Danke hab es dank euch gelöst :)
Hier mein neuer Code:

Code: Alles auswählen

def getPositions(liste,seitenabstand,randabstand):
    
    liste1=[]
    liste2=[]

    for wert in [liste]:
         Anzahl=liste[0] 
         Abstand=liste[1]
    for x in range(Anzahl):
         liste1.append(x)
          
    liste2=[(seitenabstand+(x*Abstand),randabstand) for x in liste1]
    
    return liste2
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

@carstenAC: liste ist immer noch ein schlechter Name für eine Variable, die ei Tuple mit Anzahl und Abstand ist, die erste for-Schleife ist immer noch sinnfrei, weil "wert" gar nicht verwendet wird, die Einrückung innerhalb der for-Schleifen ist immer noch 9 statt 8 Leerzeichen. Das erzeugen der liste1 ist sinnfrei, da range schon eine passende Liste liefert. liste1 ist auch kein guter Name.

Code: Alles auswählen

def get_positions(anzahl_abstand, seitenabstand, randabstand):
    anzahl, abstand = anzahl_abstand
    return [(seitenabstand + (x * Abstand), randabstand) for x in range(anzahl)]
carstenAC
User
Beiträge: 4
Registriert: Mittwoch 7. September 2016, 08:20

Hallo Sirius3,
vielen Dank. Der Code sieht viel besser aus als meiner :D .
Die Namen sind bestimmt nicht gut gewählt aber ich bin noch bei den Anfängen und es ist für mich erst einmal einfacher so.

Auf jeden Fall bin ich dir sehr dankbar.
BlackJack

@carstenAC: Gute passende Namen sind *wichtig*. Gerade auch für Anfänger. Denn wenn man einen passenden Namen sucht, muss man sich zwangsläufig Gedanken darüber machen was das wofür man den Namen sucht bedeutet. Und wenn man dabei Schwierigkeiten hat, ist das in der Regel ein Zeichen dafür das man selber nicht so ganz verstanden hat was man da in seinem eigenen Code tut. Oder das die Aufteilung/das Zusammenfassen von Daten oder Code nicht gut gewählt ist. Zum Beispiel weil man Dinge in einer Datenstruktur zusammengefasst hat, die nicht zusammen gehören, oder zusammengehörige Daten auf unterschiedliche Datenstrukturen aufgeteilt hat. Oder weil eine Funktion nicht nur *eine* Aufgabe erledigt, sondern mehrere/unterschiedliche, oder Code der *eine* Aufgabe erledigt, nicht sinnvoll auf mehr als eine Funktion aufgeteilt wurde.

Wenn man Dingen sinnvolle Namen gibt, kann man erst wirklich sinnvoll darüber nachdenken und mit anderen darüber reden. ”Andere” sind beim Programmieren oft die Programmierer die den Quelltext selbst geschrieben haben, denn wenn man nach einiger Zeit den eigenen Quelltext wieder liest, ist man selbst auf gute, passende Namen angewiesen, denn das ist alles nicht mehr so präsent im Gedächtnis wie zu der Zeit wo man es geschrieben hat und noch auswendig wusste was `liste` wohl enthalten mag.
BlackJack

@carstenAC: Um das mit den Namen noch mal zu vertiefen: Eigentlich möchte man keine Listen mit Werten deren Positionen eine bestimmte Bedeutung haben, sondern sowohl dem Datentyp als auch den einzelnen Elementen Namen geben. Dafür gibt es `collections.namedtuple()`.

Wenn man Punkte, die man ja auch als Vektoren verstehen kann, als Datentyp mit Namen und benannten Komponenten hat, dann macht es Sinn `seitenabstand` und `randabstand` zu einem Argument zusammen zu fassen, denn das ist ja eigentlich ein Vektor um den die erzeugten Positionen verschoben werden. Warum Du `anzahl` und `abstand` zu einem Argument zusammenfasst erschliesst sich mir nicht. Ich finde da keinen vernünftigen Namen für.

`get_positions()` ist eigentlich falsch, denn bei `get_*()`, also `hole_*()` erwartet man eigentlich das die Werte schon irgendwo existieren von wo sie geholt/abgefragt werden. Die Punkte werden erzeugt. Ausserdem könnte der Name auch gleich die Information enthalten, dass die Punkte alle auf einer horizontalen Linie liegen. Das könnte dann insgesamt so aussehen:

Code: Alles auswählen

from collections import namedtuple

Point = namedtuple('Point', 'x y')


def create_horizontal_points(count, distance, offset):
    return [Point(i * distance + offset.x, offset.y) for i in range(count)]
So ein Punkt-Objekt macht sowohl den Quelltext als auch die Ausgaben verständlicher als einfach zwei anonyme Werte in einer allgemeinen Liste oder einem Tupel. Zudem kann man den Wert weiterhin wie jedes andere Tupel verwenden, man kann diese Änderung also sogar einführen ohne auf einen Schlag alle Zugriffe auf die Komponenten im Quelltext ändern zu müssen:

Code: Alles auswählen

In [8]: point = Point(42, 23)

In [9]: point
Out[9]: Point(x=42, y=23)

In [10]: point.x
Out[10]: 42

In [11]: point.y
Out[11]: 23

In [12]: point[0]
Out[12]: 42

In [13]: point[1]
Out[13]: 23

In [14]: a, b = point

In [15]: a
Out[15]: 42

In [16]: b
Out[16]: 23
Da das addieren von Punkten eigentlich eine Aktion ist, die man in der Verantwortung des Punkt-Datentyps selbst sehen könnte, würde es Sinn machen eine Klasse zu schreiben die den ``+``-Operator überschreibt:

Code: Alles auswählen

class Point(namedtuple('Point', 'x y')):

    def __add__(self, other):
        return Point(self.x + other.x, self.y + other.y)


def create_horizontal_points(count, distance, offset):
    return [Point(i * distance, 0) + offset for i in range(count)]

Code: Alles auswählen

In [18]: point = Point(42, 23)

In [19]: point + Point(10, -10)
Out[19]: Point(x=52, y=13)

In [20]: create_horizontal_points(3, 5, Point(10, 20))
Out[20]: [Point(x=10, y=20), Point(x=15, y=20), Point(x=20, y=20)]
Antworten