Echte ganzzahlige Teilung

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
Benutzeravatar
Goswin
User
Beiträge: 361
Registriert: Freitag 8. Dezember 2006, 11:47
Wohnort: Ulm-Böfingen

Freitag 1. Februar 2008, 16:19

Ich arbeite mit ganzen Zahltypen, also int oder long, und moechte die Verknüpfung 'a/b' oder 'a//b' umdefinieren, da für mich weder '/' noch '//' besonders geeignet ist. Es soll nie, wie beim derzeitigen Python, ein float ausgegeben werden. Falls bei der Teilung kein Rest entsteht soll ein type(a), also ein int oder long, ausgegeben werden; und falls ein Rest übrigbleibt, soll ein IntegerDivisionError gemeldet werden:

int(k*a) / k ---> int(a) oder IntegerDivisionError
long(k*a) / k ---> long(a) oder IntegerDivisionError

Fragen:
(1) Ist es möglich '/' für normale Zahlen zu überschreiben, oder muss ich Sonderklassen <echter_int> und <echter_long> dafür benutzen? Insbesondere, kann ich zum Beispiel sicherstellen, dass <echter_int> + <int> ---> <echter_int> gilt?
(2) Muss ich sämtliche Operationen, die unverändert bleiben sollen, neu definieren, oder lassen die sich einfach über Vererbung benutzen? Ich stelle fest, dass eingebaute Klassen wie int gar keine ECHTEN Objekte sind (sie haben zum Beispiel kein __dict__-Attribut wie jedes benutzerdefiniertes Objekt).
(3) Muss ich gro3e Performanz -Einbu3en erwarten?
Benutzeravatar
BlackVivi
User
Beiträge: 762
Registriert: Samstag 9. Dezember 2006, 14:29
Kontaktdaten:

Freitag 1. Februar 2008, 16:35

Code: Alles auswählen

In [1]: from __future__ import division

In [2]: 1.5 / 1.2
Out[2]: 1.25

In [3]: 1.5 // 1.2
Out[3]: 1.0

In [4]: 1.5 // 1
Out[4]: 1.0

In [5]: 1 // 1
Out[5]: 1
.__.?
BlackJack

Freitag 1. Februar 2008, 16:56

@Goswin: Am einfachsten ist es eine entsprechende Funktion zu schreiben und die statt der Division zu verwenden. Ungetestet:

Code: Alles auswählen

def my_div(a, b):
    result, remainder = divmod(a, b)
    if remainder:
        raise ValueError('a (%r) not divisible by b (%r)' % (a, b))
    return result
lunar

Freitag 1. Februar 2008, 20:24

Goswin hat geschrieben:Fragen:
(1) Ist es möglich '/' für normale Zahlen zu überschreiben, oder muss ich Sonderklassen <echter_int> und <echter_long> dafür benutzen? Insbesondere, kann ich zum Beispiel sicherstellen, dass <echter_int> + <int> ---> <echter_int> gilt?
Zahliterale in Python sind nun mal vom Typ "int" bzw. "long". Nur weil du mal eben eine Klasse davon abgeleitet hast, definiert der Interpreter ja nicht gleich die Literaltypen um. Folglich musst du konsequent mit eigenen Objekten arbeiten. Dieser Ansatz ist höchst fehleranfällig. Vergisst du einmal, ein "int"-Objekt in deinen eigenen Typ zu konvertieren, so gibt das ja keinen Fehler, sondern ein falsches Ergebnis. Selbst mit vernünftigen Unittests ist das sehr schwer zu Debuggen.

BlackJack's Ansatz ist da auf jeden Fall besser, nicht nur zwecks Fehlervermeidung, sondern auch, um deinen Code für andere besser lesbar zu machen. Ein Python-Programmierer erwartet von / und // nämlich klar definiertes Verhalten. Werden diese Operatoren jetzt überladen, dann erleichtert das nicht gerade das Verständnis von Berechnungen.
(2) Muss ich sämtliche Operationen, die unverändert bleiben sollen, neu definieren, oder lassen die sich einfach über Vererbung benutzen? Ich stelle fest, dass eingebaute Klassen wie int gar keine ECHTEN Objekte sind (sie haben zum Beispiel kein __dict__-Attribut wie jedes benutzerdefiniertes Objekt).
In Python ist alles außer Operatoren ein Objekt! Auch int oder long. Das fehlende __dict__ Attribut tut nichts zu Sache, folgende Klasse hat ebenfalls kein __dict__:

Code: Alles auswählen

class Foo(object):
    __slots__ =  ['foo']
(3) Muss ich gro3e Performanz -Einbu3en erwarten?
Das kommt ganz darauf an, was du in den überschriebenen Operator-Methode tatsächlich machst.
Antworten