Kilometerzähler Python

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
pyNewbie666
User
Beiträge: 4
Registriert: Montag 7. Juni 2021, 14:07

Hey Leute,

ich will eine Art Kilometerzähler implementieren. Bin ziemlich neu in Programmieren und Python. Ich habe einen groben Aufbau mit doctests, aber komme nicht weiter bei der Initialisierung . Kann mir jemand helfen?
Kann man am Code erkennen was ich machen will?
LG Philipp

Code: Alles auswählen

import sys
from typing import List


class Counter:
  
    def __init__(self, max_digits: List[int]):
        """
        >>> counter = Counter([5, 9])
        >>> counter.digits()
        [0, 0]
        >>> counter = Counter([])
        >>> counter.digits()
        []
        """
        pass  

    def digits(self) -> List[int]:
        """
        >>> counter = Counter([9, 9])
        >>> counter.digits()
        [0, 0]
        >>> counter.digits()[0] += 5  #  digits soll eine kopie zurückgeben
        >>> counter.digits()
        [0, 0]
        >>> counter2 = Counter([1, 1, 1])
        >>> counter2.digits()
        [0, 0, 0]
        """
        pass  

    def increment(self):
        """
        >>> counter = Counter([1, 2])
        >>> counter.digits()
        [0, 0]
        >>> counter.increment()
        >>> counter.digits()
        [0, 1]
        >>> counter.increment()
        >>> counter.digits()
        [0, 2]
        >>> counter.increment()
        >>> counter.digits()
        [1, 0]
        >>> counter.increment()
        >>> counter.digits()
        [1, 1]
        >>> counter.increment()
        >>> counter.digits()
        [1, 2]
        >>> counter.increment()
        >>> counter.digits()
        [0, 0]
        """
        pass  

    def as_int(self) -> int:
        """
      
        >>> counter = Counter([9, 9])
        >>> counter.as_int()
        0
        >>> for _ in range(7):
        ...     counter.increment()
        >>> counter.as_int()
        7
        >>> for _ in range(35):
        ...     counter.increment()
        >>> counter.as_int()
        42
        """
        pass  

    def as_str(self) -> str:
        """
        >>> counter = Counter([9, 9])
        >>> counter.as_str()
        '00'
        >>> for _ in range(7):
        ...     counter.increment()
        >>> counter.as_str()
        '07'
        >>> for _ in range(35):
        ...     counter.increment()
        >>> counter.as_str()
        '42'
        """
        pass  


if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: counter.py <max_digit> <max_digit> … <max_digit>")
        sys.exit(1)
    pass  
 
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

`pass` braucht man nur, wenn im Block sonst nichts enthalten ist, aber Syntaktisch ein Block existieren muß. Bei Dir sind alle `pass` überflüssig.
Statt der Methoden as_int und as_str würde man die magischen Methoden __int__ und __str__ implementieren, denn das ist das, was ein Nutzer erwarten würde.

Wo kommst Du denn nicht weiter? Wo brauchst Du Hilfe?
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das sieht aber sehr nach eine Hausaufgabe aus, denn diese doc Tests schreibt keiner ohne Python-Erfahrung.

Und was daran einen Kilometerzähler darstellen soll, ist mir unklar. Das sind doch laut Tests nur überlaufende Zähler (ähnlich wie Sekunden/Minuten/Stunden).
pyNewbie666
User
Beiträge: 4
Registriert: Montag 7. Juni 2021, 14:07

Ich habe "pass" zu allen Funktionen hingeschrieben damit ich keine Fehlermeldungen bekommen. Eigentlich meine ich mit "pass" das dort noch der Code hinzugefügt werden muss. Hilfreich wäre wenn sie mir erklären könnten wie ich in def __init__ den Counter richtig initialisiere und wie ich in def digits die Werte des Counters mit Nullen überschreib :)
Danke schonmal für so eine schnelle Antwort!
pyNewbie666
User
Beiträge: 4
Registriert: Montag 7. Juni 2021, 14:07

__deets__ hat geschrieben: Montag 7. Juni 2021, 14:42 Das sieht aber sehr nach eine Hausaufgabe aus, denn diese doc Tests schreibt keiner ohne Python-Erfahrung.

Und was daran einen Kilometerzähler darstellen soll, ist mir unklar. Das sind doch laut Tests nur überlaufende Zähler (ähnlich wie Sekunden/Minuten/Stunden).
Testen ist immer das Wichtigste, habe ich beim Programmieren in C gelernt :). Ja genau ich will so eine Art überlaufender Zähler machen. Dachte durch die Tests kann man besser sehen was ich machen will.
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Nochmal: das ist offensichtlich eine Hausaufgabe. Niemand löst die hier für dich. Und niemand glaubt dir, dass du diese Doctests selbst geschrieben hast. Wenn du so abstrakt über die Funktion dieser Klasse nachdenken könntest, wäre das Problem in 2 Minuten gelöst. Von dir. Je früher du diese Charade beendest, desto besser.

Was konkret ist dir unklar? Was soll die Klasse erreichen? Wie interpretierst DU die einzelnen Tests?
pyNewbie666
User
Beiträge: 4
Registriert: Montag 7. Juni 2021, 14:07

__deets__ hat geschrieben: Montag 7. Juni 2021, 14:55 Nochmal: das ist offensichtlich eine Hausaufgabe. Niemand löst die hier für dich. Und niemand glaubt dir, dass du diese Doctests selbst geschrieben hast. Wenn du so abstrakt über die Funktion dieser Klasse nachdenken könntest, wäre das Problem in 2 Minuten gelöst. Von dir. Je früher du diese Charade beendest, desto besser.

Was konkret ist dir unklar? Was soll die Klasse erreichen? Wie interpretierst DU die einzelnen Tests?
Ok dann versuchen wir es nochmal. Was soll die Klasse erreichen? Die Klasse soll alle Ziffern von max_digits hochzählen bis alle auf 9 angelangt sind (sowie beim Kilometerzähler?).
Die Funktion def digits soll alle Ziffern des Counter auf Null setzten. Die Funktion increment soll die Ziffer am weitesten Rechts in der Liste immer um 1 erhöhen bis diese Ziffer Maximal ist und dann eins weiter nach links springen usw.
(Also von [0, 8] -> [0,9] und dann zu -> [1,0]. So habe ich es verstanden)
Die Funktionen as_int und as_str sind ja selbst erklärend.
Die Probleme die ich jetzt dabei habe sind in def __init__ und def digits. Steh ich auf dem Schlauch oder muss in def __init__ einfach nur self.max_digits = mag_digits geschrieben werden? Bei der def digits bin ich mir nicht klar wie ich alle Ziffer der Liste durch eine Null ersetzte.
Benutzeravatar
sparrow
User
Beiträge: 4164
Registriert: Freitag 17. April 2009, 10:28

pyNewbie666 hat geschrieben: Montag 7. Juni 2021, 15:33 Ok dann versuchen wir es nochmal. Was soll die Klasse erreichen? Die Klasse soll alle Ziffern von max_digits hochzählen bis alle auf 9 angelangt sind (sowie beim Kilometerzähler?).
Diese Beschreibung der Klasse entspricht nicht dem, was die Tests sagen. Oder wo siehst du im Test zu increment, dass da bei "9" etwas überläuft?
pyNewbie666 hat geschrieben: Montag 7. Juni 2021, 15:33Die Funktion def digits soll alle Ziffern des Counter auf Null setzten.
Wo genau liest du das aus den Tests ab? Auch hier sagt der test zu "increment" etwas anderes. Oder übersehe ich da, wo der Aufruf von ".digits()" etwas nullt?

Wenn du selbst nicht weißt, was die Funktionen eigentlich tun sollen... wie willst du sie dann implementieren?
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Es geht genau NICHT immer bis 9. Der Test für increments zeigt doch ganz klar, das der Überlauf bei 2 und 1 erfolgt. Da hast du also wahlweise einen schweren schizophrenen Schub gehabt, oder es ist doch eine Anforderung von jemand anderem. Was meinst du, welche dieser Schlussfolgerungen realistischer ist?

Die Klasse muss sich also merken, wieviele digits und bis zu welchem Limit die gehen. Und wo der aktuelle Zählerstand ist. Das sind als schon mal zwei Listen. Womit auch nichts mit 0 ersetzt werden muss. Was also kannst du über die Gestalt dieser Listen zum Zeitpunkt der Konstruktion sagen? Wie sehen die aus?

Die digits-Methode liefert einfach nur den aktuellen Zählerstand. Und dabei darf sie nicht einfach nur die zugrunde liegende Liste liefern. Sondern muss die kopieren.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Eine Lösung in Tcl. `digits` erledigt die meiste Arbeit, dafür ist `increment` schön einfach.

Code: Alles auswählen

package require math

oo::class create Counter {
    variable Bases ValuesCount Value
    
    constructor {maxDigits} {
        set Bases [lmap digit [lreverse $maxDigits] {incr digit}]
        set ValuesCount [math::product 1 {*}$Bases]
        set Value 0
    }

    method digits {} {
        set result {}
        set value $Value
        foreach base $Bases {
            lappend result [expr {$value % $base}]
            set value [expr {$value / $base}]
        }
        return [lreverse $result]
    }
    
    method increment {} {
        set Value [expr ($Value + 1) % $ValuesCount]
    }
    
    method asInteger {} {
        return $Value
    }
    
    method asString {} {
        return [join [my digits] ""]
    }
}
Und ein paar Unittests dazu:

Code: Alles auswählen

package require tcltest
namespace import ::tcltest::*
source counter.tcl

test counter-1 {Check if new Counter starts at all zeroes} {
    [Counter new {5 9}] digits
} {0 0}

test counter-2 {Check if new Counter with no maxDigits has no digits} {
    [Counter new {}] digits
} {}

test counter-increment-1 {Check rollover} {
    set counter [Counter new {1 2}]
    set states [list [$counter digits]]
    for {set i 0} {$i < 6} {incr i} {
        $counter increment
        lappend states [$counter digits]
    }
    return $states
} {{0 0} {0 1} {0 2} {1 0} {1 1} {1 2} {0 0}}

test counter-asInteger-1 {Check fresh counter} {
    [Counter new {9 9}] asInteger
} 0

test counter-asInteger-2 {Check incremented counter} {
    set counter [Counter new {9 9}]
    for {set i 0} {$i < 42} {incr i} {
        $counter increment
    }
    return [$counter asInteger]
} 42

test counter-asString-1 {Check fresh counter} {
    [Counter new {9 9}] asString
} "00"

test counter-asString-2 {Check incremented counter} {
    set counter [Counter new {9 9}]
    for {set i 0} {$i < 42} {incr i} {
        $counter increment
    }
    return [$counter asString]
} "42"
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Eine Python-Lösung. Naja, zumindest eine Lösung in der die Doctests funktionieren. 😛

Code: Alles auswählen

#!/usr/bin/env python3
import sys
import tkinter as tk

SOURCE = """\
package require math

oo::class create Counter {
    variable Bases ValuesCount Value
    
    constructor {maxDigits} {
        set Bases [lmap digit [lreverse $maxDigits] {incr digit}]
        set ValuesCount [math::product 1 {*}$Bases]
        set Value 0
    }

    method digits {} {
        set result {}
        set value $Value
        foreach base $Bases {
            lappend result [expr {$value % $base}]
            set value [expr {$value / $base}]
        }
        return [lreverse $result]
    }
    
    method increment {} {
        set Value [expr ($Value + 1) % $ValuesCount]
    }
    
    method asInteger {} {
        return $Value
    }
    
    method asString {} {
        return [join [my digits] ""]
    }
}
"""

_tcl = tk.Tcl()
_tcl.tk.eval(SOURCE)


class Counter:
    def __init__(self, max_digits):
        """
        >>> counter = Counter([5, 9])
        >>> counter.digits()
        [0, 0]
        >>> counter = Counter([])
        >>> counter.digits()
        []
        """
        self._tcl = _tcl
        self._counter = self._tcl.tk.call("Counter", "new", max_digits)

    def __del__(self):
        self._tcl.tk.call(self._counter, "destroy")

    def __int__(self):
        """

        >>> counter = Counter([9, 9])
        >>> int(counter)
        0
        >>> for _ in range(7):
        ...     counter.increment()
        >>> int(counter)
        7
        >>> for _ in range(35):
        ...     counter.increment()
        >>> int(counter)
        42
        """
        return self._tcl.tk.call(self._counter, "asInteger")

    def __str__(self):
        """
        >>> counter = Counter([9, 9])
        >>> str(counter)
        '00'
        >>> for _ in range(7):
        ...     counter.increment()
        >>> str(counter)
        '07'
        >>> for _ in range(35):
        ...     counter.increment()
        >>> str(counter)
        '42'
        """
        return self._tcl.tk.call(self._counter, "asString")

    def digits(self):
        """
        >>> counter = Counter([9, 9])
        >>> counter.digits()
        [0, 0]
        >>> counter.digits()[0] += 5  #  digits soll eine kopie zurückgeben
        >>> counter.digits()
        [0, 0]
        >>> counter2 = Counter([1, 1, 1])
        >>> counter2.digits()
        [0, 0, 0]
        """
        try:
            return list(self._tcl.tk.call(self._counter, "digits"))
        except TypeError:
            return []

    def increment(self):
        """
        >>> counter = Counter([1, 2])
        >>> counter.digits()
        [0, 0]
        >>> counter.increment()
        >>> counter.digits()
        [0, 1]
        >>> counter.increment()
        >>> counter.digits()
        [0, 2]
        >>> counter.increment()
        >>> counter.digits()
        [1, 0]
        >>> counter.increment()
        >>> counter.digits()
        [1, 1]
        >>> counter.increment()
        >>> counter.digits()
        [1, 2]
        >>> counter.increment()
        >>> counter.digits()
        [0, 0]
        """
        self._tcl.tk.call(self._counter, "increment")


if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: counter.py <max_digit> <max_digit> … <max_digit>")
        sys.exit(1)
    ...
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten