Seite 1 von 1
learning python: Koordinatensystem
Verfasst: Freitag 17. Januar 2014, 14:14
von NoPy
Hallo Wissende,
einige von Euch haben ja schon mit mir zu tun gehabt. Ich begann vor ca. 25 Jahren mit der Entwicklung von Software, in den letzten Jahren aber eher untergeordnet. Mit python habe ich seit wenigen Monaten und eher gelegentlich zu tun, meine Lieblingssprachen sind Pascal- Derivate und C++.
Ich habe aber beschlossen, mich intensiver in meiner Freizeit mit der Schlange zu beschäftigen. Fernziel (also irgendwann in 5 Jahren, je nachdem, wieviel Freizeit mir so bleibt

) möchte ich vielleicht mal einen Noteneditor mit Soundausgabe auf meinem Android- Tablet gebaut haben.
Habe auf einer Zugfahrt dann auch mal begonnen. Die folgende Funktion ist im Grunde so programmiert, wie ich es in anderen Sprachen auch tun würde (mal abgesehen von diversem sprachspezifischen Schnickschnack, um das zu optimieren.
Ziel ist es, aus übergebenen Achseneigenschaften (Minimum, Maximum, Schrittweite) die Achsenabschnitte für ein Koordinatensystem zu generieren, mit folgenden Besonderheiten:
- wenn nicht gerade (0,0,0) o.ä. übergeben wurde, dann soll er immer irgend etwas produzieren
- wenn die Reihenfolge vertauscht oder eine negative Schrittweite eingegeben wurde, dann soll er das auflösen
- Wenn es einen Nulldurchgang gibt, dann soll der Achsenabschnitt auch auf 0 landen
Der Code ist natürlich zugegebener Maßen sehr umständlich. (numpy hatte ich im Zug nicht, daher ohne)
Wenn jemand Lust hat, dann möge er mich belehren, wie man das in python wirklich macht.
Code: Alles auswählen
MIN_STEP_COUNT = 6.
MAX_STEP_COUNT = 20.
#import numpy
def my_range(my_min, my_max, my_step):
if my_step<0:
my_step = -my_step
if my_max < my_min:
my_min, my_max = my_max, my_min
if my_max == my_min:
my_max = my_max + MIN_STEP_COUNT * my_step
my_min = my_min - MIN_STEP_COUNT * my_step
if my_step < (my_max - my_min)/MAX_STEP_COUNT:
my_step = (my_max - my_min)/MAX_STEP_COUNT
if my_step > (my_max - my_min)/MIN_STEP_COUNT:
my_step = (my_max - my_min)/MIN_STEP_COUNT
result = []
if my_step>0:
if (my_min < 0) and (my_max > 0):
my_x = 0
while my_x > my_min:
result.append (my_x)
my_x -= my_step
my_x = my_step
while my_x < my_max:
result.append (my_x)
my_x += my_step
else:
my_x = my_step
while my_x < my_max:
result.append (my_x)
my_x += my_step
result.sort()
return result
Anmerkungen:
- my_* kommt daher, dass zumindest die Android- Variante meckerte, wenn ich max oder min verwendet habe. Also habe ich dann konsequent my_ davorgesetzt
- ich weiß, ich komme ohne "result" aus, aber da ich noch nicht sicher bin und für das debuggen ein "print result" ganz nützlich sein kann - gerade auf dem Tablet ohne Debugger - würde ich es gern behalten.
Re: learning python: Koordinatensystem
Verfasst: Freitag 17. Januar 2014, 14:31
von EyDu
Ich arbeite es einfach mal von oben nach unten ab:
- Warum sind MIN_STEP_COUNT und MAX_STEP_COUNT Konstanten? Warum existieren die überhaupt? Für mich machen die wenig Sinn.
- ``elif`` existiert, also solltest du es auch verwenden.
- Du berechnest diverse Werte doppelt. Berechne sie einmal, binde das Ergebnis an einen Namen und verwende diesen dann. Wenn du mal etwas ändern musst, dann musst du das nur an genau einer stelle und dich 6 verschiedenen.
- ``result`` sollte keine Liste sein, am besten schreibst du eine Generator-Funktion, welche mittels ``yield`` die berechneten Schritte auswirft.
- Die while-Schleifen kannst du zu einer einzigen zusammenfassen. Rechen vorher aus, wie viele Schritte du benötigst, denn Rest kannst du dan parametrisieren.
- Was macht der sort-Aufruf da am Ende? Wenn du auch Schritte rückwärts machen willst, dann ist das sehr kontraproduktiv. Wenn du keine Schritte Rückwärts machen willst, dann musst du, wie beim Punkt vorher erwähnt, entsprechend konvertieren.
Edit: Ach ja, die ganzen ``my``s solltest du lassen, das ist ech gruselig. Wenn du mit den Namen mit und max Probleme hattest, dann nenne sie low und high oder min_ und_ max_.
Re: learning python: Koordinatensystem
Verfasst: Freitag 17. Januar 2014, 14:47
von p90
Also wenn ich das richtig verstehe möchtest du pythons "range" nachprogrammieren
mit einer minimalen und maximalen Anzahl an schritten?
Fall du Range nicht kennts:
http://docs.python.org/3.3/library/stdt ... sseq-range
hier mal ein paar Zeilen die dir vlt. Ideen geben
Code: Alles auswählen
MIN_STEP_COUNT = 6.
MAX_STEP_COUNT = 20.
def my_range(border1, border2, my_step=1):
range_min = min(border1, border2)
range_max = max(border1, border2)
step = my_step if my_step else -my_step
tmp = []
if step:
#step ist nicht 0
if range_min == range_max:
range_max = range_max + MIN_STEP_COUNT * step
range_min = range_min - MIN_STEP_COUNT * step
stepnumber = (range_max - range_min) / step
step = step if stepnumber < MAX_STEP_COUNT else (range_max - range_min)/MAX_STEP_COUNT
step = step if stepnumber > MIN_STEP_COUNT else (range_max - range_min)/MIN_STEP_COUNT
#tmp = list(range(range_min, range_max, step))
#wenn du range nehmen möchtest
#ansonsten vlt so?
i = range_min
while i < range_max:
tmp.append(i)
i += step
return tmp
Ansonsten guck auf meinen Vorposter.
Re: learning python: Koordinatensystem
Verfasst: Freitag 17. Januar 2014, 14:54
von NoPy
- mit MIN_STEP_COUNT und MAX_STEP_COUNT will ich "verhindern", dass ich zu viele Abschnitte kriege, eben nicht weniger als 6, nicht mehr als 20. Das lief ja erst mal im Textfenster, irgendwann begrenzt sich das dann durch die Bildschirmgröße. Oder anders: Das ist Absicht.
- elif funktioniert nur bei Zeile 14 und 16, in allen anderen Fällen muss der vorige if- Zweig durchlaufen werden
- an welchen Stellen berechne ich etwas doppelt? Ich hätte die While- Schleifen zusammentricksen können, aber etwas anderes sehe ich nicht. Ich könnte sozusagen einen Verschiebungsvektor berechnen, damit ich genau auf 0 komme, aber liest sich das dann noch? Macht man das so in python?
- sort ist nur dafür da, weil ich in einem Fall die negativen Werte rückwärts dranhänge. Könnte ich auch sparen, aber liest es sich so nicht besser?
- ehe ich solange probiere, bis ein Name passt (wer weiß, wann low und high auf Widerstand stoßen) nenne ich sie lieber my_ und max_ und min_ erscheint mir ehrlich gesagt im Moment noch grusliger. Dann würde ich eher ausnutzen, dass python englisch spricht und kleinste, groesste und schrittweite verwenden
Re: learning python: Koordinatensystem
Verfasst: Freitag 17. Januar 2014, 15:05
von EyDu
NoPy hat geschrieben:mit MIN_STEP_COUNT und MAX_STEP_COUNT will ich "verhindern", dass ich zu viele Abschnitte kriege, eben nicht weniger als 6, nicht mehr als 20. Das lief ja erst mal im Textfenster, irgendwann begrenzt sich das dann durch die Bildschirmgröße. Oder anders: Das ist Absicht.
Dann schicke die Werte als Parameter mit Default-Werten in die Funktion
NoPy hat geschrieben:elif funktioniert nur bei Zeile 14 und 16, in allen anderen Fällen muss der vorige if- Zweig durchlaufen werden
Und bei Zeile 9 und 11.
NoPy hat geschrieben:an welchen Stellen berechne ich etwas doppelt? Ich hätte die While- Schleifen zusammentricksen können, aber etwas anderes sehe ich nicht. Ich könnte sozusagen einen Verschiebungsvektor berechnen, damit ich genau auf 0 komme, aber liest sich das dann noch? Macht man das so in python?
Deine drei while-Schleifen sind alle quasi identisch. Zum zusammenfassen musst du auch nichts zusammenbasteln, sonder nur ein wenig nachdenken
NoPy hat geschrieben:sort ist nur dafür da, weil ich in einem Fall die negativen Werte rückwärts dranhänge. Könnte ich auch sparen, aber liest es sich so nicht besser?
Du must in deinem Code vorher dafür sorgen, dass dieser Fall gar nicht erst auftreten kann.
NoPy hat geschrieben:he ich solange probiere, bis ein Name passt (wer weiß, wann low und high auf Widerstand stoßen) nenne ich sie lieber my_ und max_ und min_ erscheint mir ehrlich gesagt im Moment noch grusliger. Dann würde ich eher ausnutzen, dass python englisch spricht und kleinste, groesste und schrittweite verwenden
Dann werfe ich mal noch start und stop in den Raum. Die englische Sprache bietet hier sicher noch jede Menge weiterer Alternativen.
Re: learning python: Koordinatensystem
Verfasst: Freitag 17. Januar 2014, 15:09
von NoPy
@P90: Danke auch für Dein Posting, aber wirklich kürzer und einleuchtender finde ich es nicht, wenn ich ehrlich bin, zumal es ja die Spezifikation nicht erfüllt:
Wenn der Bereich über 0 hinweg geht, soll zwingend die 0 als Wert in der Liste erscheinen.
Beispiel: my_range(-11,5,2)
meine Version: [-10, -8, -6, -4, -2, 0, 2, 4]
deine Version: [-11, -9, -7, -5, -3, -1, 1, 3]
Die Schrittweite soll nur korrigiert werden, wenn sie aus dem Rahmen fällt
Beispiel: my_range(0,100,15)
meine Version: [15, 30, 45, 60, 75, 90]
deine Version: [0, 16.666666666666668, 33.333333333333336, 50.0, 66.66666666666667, 83.33333333333334]
Alles andere ist im Grunde identisch, dass bei Dir die Untergrenze immer dabei ist und die Obergrenze immer fehlt und bei mir prinzipiell beide Grenzen fehlen ist so oder so überarbeitungsbedürftig.
@EyDu: Mit Generatorfunktionen muss ich mich sicher noch beschäftigen. Der Vorteil wäre in diesem Fall aber welcher?
Re: learning python: Koordinatensystem
Verfasst: Freitag 17. Januar 2014, 15:24
von NoPy
EyDu hat geschrieben:Dann schicke die Werte als Parameter mit Default-Werten in die Funktion
Ungern, weil diese Parameter ja de facto nie verändert werden sollen. Aber wenn es Dir besser gefällt, mach ich das Gern. Darauf kommt es mir hier nicht an. Irgendwann in einem Gesamtprojekt gäbe es quasi "Einstellungen", die solches Verhalten steuern. Und ob ich dann alle Funktionen, die an den gleichen Einstellungen hängen, mit diesen Parametern beschicke oder die Parameter gleich aus den Einstellungen geholt werden, das ist mir letztlich erst einmal gleich.
EyDu hat geschrieben:Und bei Zeile 9 und 11.
stimmt.
EyDu hat geschrieben:
Deine drei while-Schleifen sind alle quasi identisch. Zum zusammenfassen musst du auch nichts zusammenbasteln, sonder nur ein wenig nachdenken
Wie gesagt, ich müsste ein Offset berechnen, das vom Anfang, Ende und Schrittweite abhängt. Was gewinne ich dadurch? Die Anzahl der Schleifendurchläufe bleibt identisch, ich habe eine komplizierte Berechnung und eine Schleifenendbedingung statt zweier (bzw. dreier) einfacherer Berechnungen und 2 Schleifenendbedingungen. Unter dem Aspekt der Wartbarkeit erschiene mir das nur sinnvoll, wenn innerhalb der Schleife komplizierte Dinge stattfinden würden, oder?
EyDu hat geschrieben:
Du must in deinem Code vorher dafür sorgen, dass dieser Fall gar nicht erst auftreten kann.
Das könnte ich, aber auch das wäre eine kompliziertere und damit fehleranfälligere Formel, als hinterher zu sortieren. Wenn man nach dem KISS- Prinzip verfährt, sollte sich das doch verbieten, oder? Alternativ müsste ich schreiben:
my_x = int(min_x / my_step)*my_step und dann bis 0 zählen.
EyDu hat geschrieben:Dann werfe ich mal noch start und stop in den Raum. Die englische Sprache bietet hier sicher noch jede Menge weiterer Alternativen.
Das Problem bei solchen bezeichnern ist, dass sie immer irgendwann mit irgendetwas kollidieren und ich dann wieder probieren muss. Dazu kommt, dass die englischen Bezeichner wesentlich unspezifischer sind, als die Bezeichner anderer Sprachen, was in der Programmierung eigentlich kein Zugewinn ist. Aber nun gut, es ist usus.
Re: learning python: Koordinatensystem
Verfasst: Freitag 17. Januar 2014, 15:33
von p90
NoPy hat geschrieben:@P90: Danke auch für Dein Posting, aber wirklich kürzer und einleuchtender finde ich es nicht, wenn ich ehrlich bin, zumal es ja die Spezifikation nicht erfüllt:
Wenn der Bereich über 0 hinweg geht, soll zwingend die 0 als Wert in der Liste erscheinen.
Ah, das hatte ich übersehen, lässt sich aber sehr leicht mit einem if in der while Schleife beheben.
Ansonsten hast du bei mir halt nur eine While Schleife statt 3 und die ganze Behandelung von
Sonderfällen in riesigen If zweigen fällt weg.
Was meinst du genau mit Unübersichtlich?
VLt. die conditional binds die ich verwende?
NoPy hat geschrieben:
Die Schrittweite soll nur korrigiert werden, wenn sie aus dem Rahmen fällt
Beispiel: my_range(0,100,15)
meine Version: [15, 30, 45, 60, 75, 90]
deine Version: [0, 16.666666666666668, 33.333333333333336, 50.0, 66.66666666666667, 83.33333333333334]
In meiner Version ist sie ja aus dem Rahmen gefallen, da ich mich an range orientiert habe und das nimmt als erstes Element immer die untere Schranke. Und das ist je genau das gewollte verhalten oder? Die Versionen unterscheiden sicht halt genau um 1 was die Zählweise der Schritte angeht.
Re: learning python: Koordinatensystem
Verfasst: Freitag 17. Januar 2014, 15:40
von NoPy
Hab mal eine erste Anpassung vorgenommen
Code: Alles auswählen
def my_range(kleinster, groesster, schritt):
schritt = schritt if schritt else - schritt
if schritt<0:
schritt = -schritt
if groesster < kleinster:
kleinster, groesster = groesster, kleinster
elif groesster == kleinster:
groesster = groesster + MIN_STEP_COUNT * schritt
kleinster = kleinster - MIN_STEP_COUNT * schritt
if schritt < (groesster - kleinster)/MAX_STEP_COUNT:
schritt = (groesster - kleinster)/MAX_STEP_COUNT
if schritt > (groesster - kleinster)/MIN_STEP_COUNT:
schritt = (groesster - kleinster)/MIN_STEP_COUNT
result = []
if schritt>0:
if (kleinster < 0) and (groesster > 0):
x = round(kleinster / schritt + 0.5)*schritt
else:
x = kleinster
while x <= groesster:
result.append (x)
x += schritt
return result
Re: learning python: Koordinatensystem
Verfasst: Freitag 17. Januar 2014, 15:49
von NoPy
[quote="p90"]Was meinst du genau mit Unübersichtlich?
[quote="NoPy"]
Das mit der Schrittweite am Anfang ist eine Verbesserung:
Aber die Beachtung der Randbedingungen MIN_STEP_COUNT, MAX_STEP_COUNT finde ich persönlich unübersichtlich. Vermutlich ist das Geschmackssache, fürchte ich. Denn im Grunde ist es ja das gleiche, wie oben
Und die neuen Variablen range_min und .. max brauche ich ja auch nicht, wenn ich die anderen beiden vertausche.
Re: learning python: Koordinatensystem
Verfasst: Freitag 17. Januar 2014, 15:55
von Sirius3
Am besten ist es, ein Range-Objekt ähnlich einem xrange-Objekt zu erzeugen. Es verhält sich weitgehend so wie eine Liste, braucht aber nicht den Speicher einer Liste:
Code: Alles auswählen
class Range(object):
def __init__(self, start, stop, step, min_step_count=6, max_step_count=20):
start, stop = sorted([start, stop])
step = abs(step)
if start == stop:
start -= min_step_count * step
self.stop += min_step_count * step
min_step = (stop-start) / max_step_count
max_step = (stop-start) / min_step_count
step = sorted([min_step, step, max_step])[1]
self.min_step_count = min_step_count
self.max_step_count = max_step_count
self.start = step * math.floor(start / step)
self.stop = step * math.ceil(stop / step)
self.step = step
self.step_count = round((stop-start)/step)
def __iter__(self):
for i in xrange(self.step_count):
yield self.start + i * self.step
def __getitem__(self, index):
if index<0 or index>=self.step_count:
raise IndexError('index out of range')
return self.start + index * self.step
def __len__(self):
return self.step_count
Re: learning python: Koordinatensystem
Verfasst: Freitag 17. Januar 2014, 15:56
von EyDu
Schon deutlich schöner. Aber was versprichst du dir von Zeile zwei in deinem Code? Zeile 15 sollte jetzt auch überflüssig sein, die Bedingung ist immer erfüllt.
Code: Alles auswählen
def my_range(
kleinster, groesster, schritt,
min_step_count=MIN_STEP_COUNT,
max_step_count=MAX_STEP_COUNT):
schritt = abs(schritt)
if groesster < kleinster:
kleinster, groesster = groesster, kleinster
elif groesster == kleinster:
kleinste_breite = min_step_count * schritt
groesster = groesster + kleinste_breite
kleinster = kleinster - kleinste_breite
breite = groesster - kleinster
kleinster_schritt, groesster_schritt = breite/max_step_count, breite/min_step_count
if schritt < kleinster_schritt:
schritt = kleinster_schritt
if schritt > groesster_schritt:
schritt = groesster_schritt
if (kleinster < 0) and (groesster > 0):
x = round(kleinster / schritt + 0.5)*schritt
else:
x = kleinster
while x <= groesster:
yield x
x += schritt
Bzw. dann noch weiter vereinfacht:
Code: Alles auswählen
def my_range(
kleinster, groesster, schritt,
min_step_count=MIN_STEP_COUNT,
max_step_count=MAX_STEP_COUNT):
schritt = abs(schritt)
if groesster < kleinster:
kleinster, groesster = groesster, kleinster
elif groesster == kleinster:
kleinste_breite = min_step_count * schritt
groesster = groesster + kleinste_breite
kleinster = kleinster - kleinste_breite
breite = groesster - kleinster
kleinster_schritt, groesster_schritt = breite/max_step_count, breite/min_step_count
schritt = min(max(kleinster_schritt, schritt), groester_schritt)
if (kleinster < 0) and (groesster > 0):
x = round(kleinster / schritt + 0.5)*schritt
else:
x = kleinster
while x <= groesster:
yield x
x += schritt
Re: learning python: Koordinatensystem
Verfasst: Freitag 17. Januar 2014, 16:05
von pillmuncher
Ich werfe mal das hier in den Ring:
Code: Alles auswählen
MIN_STEP_COUNT = 6.
MAX_STEP_COUNT = 20.
def my_range(lo, hi, step):
step = abs(step)
if lo > hi:
lo, hi = hi, lo
elif lo == hi:
hi += MIN_STEP_COUNT * step
lo -= MIN_STEP_COUNT * step
if step < (hi - lo) / MAX_STEP_COUNT:
step = (hi - lo) / MAX_STEP_COUNT
elif step > (hi - lo) / MIN_STEP_COUNT:
step = (hi - lo) / MIN_STEP_COUNT
if step == 0:
return []
result = []
if lo < 0 < hi:
x = 0
while x > lo:
result.append(x)
x -= step
result = result[::-1]
x = step
while x < hi:
result.append(x)
x += step
return result
Algorithmisch habe ich nichts geändert. Ich habe es nur etwas pythonischer gemacht.
Sowohl im Original-Code, als auch in meiner Version, ist IMO ein Bug: Wenn
lo < 0 und
hi < 0 und
lo != hi, dann ist das Ergebnis
[].
Re: learning python: Koordinatensystem
Verfasst: Freitag 17. Januar 2014, 16:07
von NoPy
Muss leider erst mal schluss machen. Kurz überflogen: Interessantes dabei.
@sirius: Bist Du Dir sicher, dass Du dich zwischen stop / self.stop und start / self.start nicht verhaspelt hast?
Mir ging es schon öfter so und bei Dir habe ich zumindest in den Zeilen 6 und 7 auch das Gefühl.
Code: Alles auswählen
start -= min_step_count * step
self.stop += min_step_count * step
Den Rest muss ich mir später ansehen.
Re: learning python: Koordinatensystem
Verfasst: Freitag 17. Januar 2014, 16:25
von p90
Sehe gerade noch einen blöden Fehler in meinem Code:
Und zwar:
verändert a niemals.
Hintergrund:
Der boolische Wert für a ist:
False falls a = 0
True für JEDEN anderen Fall
es ergibt sich also für negative Zahlen folgendes:
Ergo ist a danach immer noch -5 statt 5
Möchte man das Vorzeichen ändern sollte man also direkt die Richtige Funktion nehmen und
verwenden.
Re: learning python: Koordinatensystem
Verfasst: Freitag 17. Januar 2014, 16:34
von pillmuncher
Den
o.g. Bug kann man leicht richten, und damit lässt es sich es auch einfacher zum Generator umbauen:
Code: Alles auswählen
MIN_STEP_COUNT = 6.
MAX_STEP_COUNT = 20.
def my_range(lo, hi, step):
step = abs(step)
if lo > hi:
lo, hi = hi, lo
elif lo == hi:
hi += MIN_STEP_COUNT * step
lo -= MIN_STEP_COUNT * step
if step < (hi - lo) / MAX_STEP_COUNT:
step = (hi - lo) / MAX_STEP_COUNT
elif step > (hi - lo) / MIN_STEP_COUNT:
step = (hi - lo) / MIN_STEP_COUNT
if step <= 0:
return
if lo < 0 < hi:
offset = lo % step
lo -= offset
hi -= offset
x = lo
while x < hi:
yield x
x += step
Re: learning python: Koordinatensystem
Verfasst: Freitag 17. Januar 2014, 18:32
von pillmuncher
Habe noch zwei Bugs im
Code gefunden.
Dieser ist vielleicht ein Feature:
Code: Alles auswählen
>>> print my_range(10, 20, 3)
[1.6666666666666667, 3.3333333333333335, 5.0, 6.666666666666667, 8.333333333333334, 10.0, 11.666666666666666, 13.333333333333332, 14.999999999999998, 16.666666666666664, 18.333333333333332]
Dieser wohl nicht:
Da landet man in einer Endlosschleife.
Wahrscheinlich hat der OP nicht gar damit gerechnet, dass jemand die Funktion mit floating point Argumenten aufrufen würde. Er schrieb ja, dass er von statisch typisierten Sprachen kommt. Für alle anderen gilt, was ich heute zufällig gelesen habe:
Some programmers, when confronted with a problem, think "I know, I'll use floating point arithmetic." Now they have 1.999999999997 problems.
Re: learning python: Koordinatensystem
Verfasst: Samstag 18. Januar 2014, 09:19
von pillmuncher
Nur, damit ich sicher sein kann, dass ich die Spezifikation der Funktion auch verstanden habe. Gegeben drei Zahlen
a,
b und
c mit
lo = min(a, b) und
hi = max(a, b) und
step = abs(c) und
num_steps = (hi - lo) / step und dazu zwei Konstanten
MIN und
MAX mit
MIN < MAX, dann gilt:
Code: Alles auswählen
lo == hi or lo < hi
lo <= hi < 0 or lo <= 0 <= hi or 0 < lo <= hi
num_steps < MIN or MIN <= num_steps <= MAX or MAX < num_steps
0 == step or 0 < step
Da
num_steps nicht existiert, sofern
step == 0 ist, ergeben sich daraus 2 * 3 + 2 * 3 * 3 == 24 Kombinationen. Was soll im jeweiligen Fall geschehen?