Hallo,
ich habe folgendes Problem:
Ich bekomme bei meinem Programm in der Console folgende Ausgabe:
999
Wenn ich einen Docktest für das Programm schreibe erhalte ich:
Expected:
Hier steht ein Tab bzw. Whitespaces 999
Got:
999
Doctest Whitespace
@Vega: Ein Tab sollte da nicht stehen, und halt auch nicht zu viele Leerzeichen.
Ja, das wundert mich ja gerade, weiß jemand was da passiert ist bzw. was ich machen kann?
>>> counter([1, 5, 6])
156
das ist z.B. eine meiner Doctests
und jetzt steht da:
Test failed..
Expected:
hier wieder die Leerzeichen 156
Got:
156
Also vor dem erwarteten Wert, werden einfach Lesezeichen eingefügt..
>>> counter([1, 5, 6])
156
das ist z.B. eine meiner Doctests
und jetzt steht da:
Test failed..
Expected:
hier wieder die Leerzeichen 156
Got:
156
Also vor dem erwarteten Wert, werden einfach Lesezeichen eingefügt..
@Vega: Die werden da nicht einfach eingefügt, die werden da schon so stehen. Zeig doch mal ein komplettes Beispiel das man nachvollziehen kann. Also einen kompletten Code auf den man Doctest loslassen kann, wo dieses Problem auftritt.
Wenn ich zum Beispiel das hier habe:
Hat `doctest` kein Problem damit:
[codebox=text file=Unbenannt.txt]$ python -m doctest -v forum3.py
Trying:
counter([1, 5, 6])
Expecting:
156
ok
1 items had no tests:
forum3
1 items passed all tests:
1 tests in forum3.counter
1 tests in 2 items.
1 passed and 0 failed.
Test passed.[/code]
Wenn ich zum Beispiel das hier habe:
Code: Alles auswählen
def counter(items):
"""
>>> counter([1, 5, 6])
156
"""
return int(''.join(map(str, items)))
[codebox=text file=Unbenannt.txt]$ python -m doctest -v forum3.py
Trying:
counter([1, 5, 6])
Expecting:
156
ok
1 items had no tests:
forum3
1 items passed all tests:
1 tests in forum3.counter
1 tests in 2 items.
1 passed and 0 failed.
Test passed.[/code]
Code: Alles auswählen
value = int(''.join(str(k) for k in lst))
print("%i" % value, end='\r')
nun habe ich wie oben, den Doctest.
Du sagst ja, dass die Leerzeichen da stehen, aber das Expected geb ich ja ein, also müsste ich die Leerzeichen hingeschrieben haben, was ich jedoch nicht habe.
Das Programm gibt die richtige Ausgabe, nur das Expected des Tests ist falsch oder verstehe ich da was falsch?
Danke im voraus =)
Zuletzt geändert von Anonymous am Mittwoch 7. Juni 2017, 16:36, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Das ist doch schon wieder kein kompletter Code, den man selbst durch einen Doctest jagen kann. Insofern - doch, das was davor ist, tut zur Sache. Mit irgendwelchen Codeschnipseln die noch nicht mal selbststaendig lauffaehig sind kann hier niemand etwas anfangen.
@Vega: In Deinem Doctest wird eine Funktion `counted()` aufgerufen. In dem Quelltext sehe ich diese Funktion nicht. Und gibt Deine Funktion etwas zurück oder gibt sie etwas aus? Wenn Du versuchst die Ausgabe zu prüfen, dann muss der Vergleichswert genau so aussehen — ich frage mich gerade wie man einen Wagenrücklauf so normal mit einem Editor in die Datei bekommt, ohne ein Zeilenende und Doctest so etwas überhaupt sinnvoll prüfen könnte.
Code: Alles auswählen
class Counter:
"""
>>> counter = Counter([9, 9, 9])
>>> counter.increment()
>>> counter.count
[0, 0, 1]
>>> counter.count = [0, 9, 9]
>>> counter.increment()
>>> counter.count
[1, 0, 0]
>>> counter.increment()
>>> counter.count
[1, 0, 1]
>>> counter = Counter([2, 3, 4])
>>> counter.count = [2, 3, 4]
>>> counter.increment()
>>> counter.count
[0, 0, 1]
"""
def __init__(self, lst):
self.count = [0] * len(lst)
self.lst = lst
def increment(self):
self.count[len(self.count) - 1] += 1
for i in range(len(self.count) - 1, -1, -1):
if self.count[i] > self.lst[i]:
self.count[i] = 0
self.count[i - 1] += 1
else:
break
def maximum(lst):
"""
Increments the counter while until the counter has reached the maximum.
:param lst: list of maximums for the counter
:return: all counter values until the maximum
>>> maximum([1, 1, 1])
111
>>> maximum([2, 1 ,0])
210
>>> maximum([1, 1 ,0])
110
"""
counter = Counter(lst)
for i in range(0, len(lst)):
while counter.count[i] != lst[i]:
counter.increment()
# print the current counter values
countervalues = int(''.join(str(k) for k in counter.count))
print("%i" % countervalues, end='\r')
Also wird es doch nicht am Code liegen oder sehe ich das falsch?
@Vega: Das unterscheidet sich durch deutlich mehr als rein durch Whitespace. Ich bekomme da:
[codebox=text file=Unbenannt.txt]$ python3 -m doctest Dropbox/forum2.py
**********************************************************************
File "Dropbox/forum2.py", line 44, in forum2.maximum
Failed example:
maximum([1, 1, 1])
Expected:
111
Got:
111 1
**********************************************************************
File "Dropbox/forum2.py", line 47, in forum2.maximum
Failed example:
maximum([2, 1 ,0])
Expected:
210
Got:
210 10
**********************************************************************
File "Dropbox/forum2.py", line 50, in forum2.maximum
Failed example:
maximum([1, 1 ,0])
Expected:
110
Got:
110 10
**********************************************************************
1 items had failures:
3 of 3 in forum2.maximum
***Test Failed*** 3 failures.[/code]
Das beim ``Got:`` am Anfang keine Leerzeichen stehen, dürfte daran liegen, dass Du explizit einen Wagenrücklauf ohne Zeilenvorschub ausgibst.
Bei der `maximum()`-Funktion stimmt der dokumentierte Rückgabewert nicht. Die Funktion gibt *nichts* zurück. Die gibt nur etwas aus.
Bei den Doctests stimmen zudem die Erwartungen nicht, denn wenn man das tatsächlich aufruft, dann müsste bei drei Stellen am Ende ja immer 999 da stehen und nicht der Startwert. Allerdings würde die Funktion diese Zahlen alle übereinander ausgeben, also immer die letzte Ausgabe überschreiben. Das sind aber alles Daten die ausgegeben werden, also von Doctest auch berücksichtigt werden. Dummerweise wird man das so nicht in die Textdatei schreiben können. Jedenfalls nicht mit jedem Editor. Und wie das dann im Texteditor und anderswo (zum Beispiel hier im Forum) angezeigt würde, wäre sicher auch spannend. Zudem möchte man diese ganzen Daten sicher nicht eintippen.
`Counter.count` sollte besser `Counter.digits` heissen, denn das sind ja Ziffern des `Counter`. Und `lst` sagt ja gar nichts darüber aus was der Wert bedeutet. `max_digits` wäre vielleicht eine Idee.
Nach 999 folgt 001? Ich hätte da ja 000 erwartet.
Ob die `maximum()`-Funktion tatsächlich das macht was sie soll, wage ich zu bezweifeln.
Das Umwandeln in Zeichenkette und Zahl würde ich in die `Counter`-Klasse verlegen. `__str__()` und `__int__()` bieten sich da geradezu an. Falls der Test *eigentlich* testen soll ob der `Counter` sein Maximum erreicht hat, dann würde ich den Test auch als Methode in die Klasse verschieben.
[codebox=text file=Unbenannt.txt]$ python3 -m doctest Dropbox/forum2.py
**********************************************************************
File "Dropbox/forum2.py", line 44, in forum2.maximum
Failed example:
maximum([1, 1, 1])
Expected:
111
Got:
111 1
**********************************************************************
File "Dropbox/forum2.py", line 47, in forum2.maximum
Failed example:
maximum([2, 1 ,0])
Expected:
210
Got:
210 10
**********************************************************************
File "Dropbox/forum2.py", line 50, in forum2.maximum
Failed example:
maximum([1, 1 ,0])
Expected:
110
Got:
110 10
**********************************************************************
1 items had failures:
3 of 3 in forum2.maximum
***Test Failed*** 3 failures.[/code]
Das beim ``Got:`` am Anfang keine Leerzeichen stehen, dürfte daran liegen, dass Du explizit einen Wagenrücklauf ohne Zeilenvorschub ausgibst.
Bei der `maximum()`-Funktion stimmt der dokumentierte Rückgabewert nicht. Die Funktion gibt *nichts* zurück. Die gibt nur etwas aus.
Bei den Doctests stimmen zudem die Erwartungen nicht, denn wenn man das tatsächlich aufruft, dann müsste bei drei Stellen am Ende ja immer 999 da stehen und nicht der Startwert. Allerdings würde die Funktion diese Zahlen alle übereinander ausgeben, also immer die letzte Ausgabe überschreiben. Das sind aber alles Daten die ausgegeben werden, also von Doctest auch berücksichtigt werden. Dummerweise wird man das so nicht in die Textdatei schreiben können. Jedenfalls nicht mit jedem Editor. Und wie das dann im Texteditor und anderswo (zum Beispiel hier im Forum) angezeigt würde, wäre sicher auch spannend. Zudem möchte man diese ganzen Daten sicher nicht eintippen.
`Counter.count` sollte besser `Counter.digits` heissen, denn das sind ja Ziffern des `Counter`. Und `lst` sagt ja gar nichts darüber aus was der Wert bedeutet. `max_digits` wäre vielleicht eine Idee.
Nach 999 folgt 001? Ich hätte da ja 000 erwartet.
Ob die `maximum()`-Funktion tatsächlich das macht was sie soll, wage ich zu bezweifeln.
Das Umwandeln in Zeichenkette und Zahl würde ich in die `Counter`-Klasse verlegen. `__str__()` und `__int__()` bieten sich da geradezu an. Falls der Test *eigentlich* testen soll ob der `Counter` sein Maximum erreicht hat, dann würde ich den Test auch als Methode in die Klasse verschieben.
Code: Alles auswählen
class Counter:
"""
>>> counter = Counter([9, 9, 9])
>>> counter.increment()
>>> counter.count
[0, 0, 1]
>>> counter.count = [0, 9, 9]
>>> counter.increment()
>>> counter.count
[1, 0, 0]
>>> counter.increment()
>>> counter.count
[1, 0, 1]
>>> counter = Counter([2, 3, 4])
>>> counter.count = [2, 3, 4]
>>> counter.increment()
>>> counter.count
[0, 0, 0]
"""
def __init__(self, lst):
self.count = [0] * len(lst)
self.lst = lst
def increment(self,):
if self.count == self.lst:
self.count = [0] * len(self.lst)
else:
self.count[len(self.count) - 1] += 1
for i in range(len(self.count) - 1, -1, -1):
if self.count[i] > self.lst[i]:
self.count[i] = 0
self.count[i - 1] += 1
else:
break
def maximum(lst):
"""
Increments the counter while until the counter has reached the maximum.
:param lst: list of maximums for the counter
:return: all counter values until the maximum
>>> maximum([1, 1, 1])
111
>>> maximum([2, 1 ,0])
210
>>> maximum([1, 1 ,0])
110
"""
counter = Counter(lst)
for i in range(0, len(lst)):
while counter.count[i] != lst[i]:
counter.increment()
# print the current counter values
countervalues = int(''.join(str(k) for k in counter.count))
print("%i" % countervalues, end='\r')
if __name__ == '__main__':
maximum([99, 99, 99])
Und die Maximum Funktion, bekommt eine Liste, welche das Maximum angibt, diese Funktion zählt nun von 0 hoch, bis dieser Wert erreicht wurde.
Wie würdest du den die Zahlen in Zeichenketten umwandeln in der Klasse?
Und wie sorge ich dafür, dass es mir diesen Zeilenvorschub bei 'Got' ausgibt.
Ich erhalte bei den Test folgendes:
Code: Alles auswählen
Failed example:
maximum([1, 1, 1])
Expected:
111
Got:
111
@Vega: Umwandeln in Zeichenkette geht in der Klasse genau so wie ausserhalb. Wenn man `__str__()` und `__int__()` implementiert, hat man halt den Vorteil, dass man dem Standardweg folgt wie man Objekte in eine Zeichenkettendarstellung oder eine ganze Zahl umwandelt. Man kann die Objekte dann beispielsweise einfach mit `print()` ausgeben, oder in mit der `format()`-Methode in eine Zeichenkette formatieren wenn das Objekt selbst weiss wie es in eine Zeichenkette umgewandelt werden kann.
Mindestens zusätzlich zu `increment()` würde ich das erhöhen des Zählers auch unter dem Namen `__next__()` zur Verfügung stellen. Dann kann man `Counter`-Objekte auch in ``for``-Schleifen verwenden.
Der Doctest wird mit diesem Code gar nicht gehen, weil Du den erwarteten Text nicht eingeben kannst. Der ist ja nicht 110, sondern '0\r1\r2\r3\r4\r…\r110\r' aber eben nicht als Zeichenkettenliteral, sondern wirklich mit diesen Steuerzeichen im Quelltext. Selbst bei Editoren mit denen man das eingeben *kann* (Vim zum Beispiel), *möchte* man das sicher nicht, denn man müsste da ja 110 Zahlen eintippen. Und *lesen* möchte das sicher niemand. Zumal da auch das Problem der Darstellung dazu kommt. Im Editor, und vielleicht auch in generierten HTML, PDF, ePub, … Dokumenten.
Problematisch ist die Vermischung von Programmlogik und Benutzerinteraktion. Wenn man beispielsweise eine Generatorfunktion hätte, die alle Werte als Elemente liefert statt sie auszugeben, dann könnte man das recht einfach prüfen, mit einem Docstring wie dem hier beispielsweise:
Ansonsten müsste man die Funktion aus den Doctests halt einfach ausnehmen.
Edit: `maximum()` ist wirklich an sehr schlechter Name für die Funktion!
Mindestens zusätzlich zu `increment()` würde ich das erhöhen des Zählers auch unter dem Namen `__next__()` zur Verfügung stellen. Dann kann man `Counter`-Objekte auch in ``for``-Schleifen verwenden.
Der Doctest wird mit diesem Code gar nicht gehen, weil Du den erwarteten Text nicht eingeben kannst. Der ist ja nicht 110, sondern '0\r1\r2\r3\r4\r…\r110\r' aber eben nicht als Zeichenkettenliteral, sondern wirklich mit diesen Steuerzeichen im Quelltext. Selbst bei Editoren mit denen man das eingeben *kann* (Vim zum Beispiel), *möchte* man das sicher nicht, denn man müsste da ja 110 Zahlen eintippen. Und *lesen* möchte das sicher niemand. Zumal da auch das Problem der Darstellung dazu kommt. Im Editor, und vielleicht auch in generierten HTML, PDF, ePub, … Dokumenten.
Problematisch ist die Vermischung von Programmlogik und Benutzerinteraktion. Wenn man beispielsweise eine Generatorfunktion hätte, die alle Werte als Elemente liefert statt sie auszugeben, dann könnte man das recht einfach prüfen, mit einem Docstring wie dem hier beispielsweise:
Code: Alles auswählen
>>> xs = list(maximum([1, 1, 0]))
>>> xs[:12]
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11']
>>> xs[98:102]
['98', '99', '100', '101']
>>> xs[-1]
'110'
Edit: `maximum()` ist wirklich an sehr schlechter Name für die Funktion!