2017-02-17 5 views
1

Ich komme von Racket zu Python. In Racket, würde ich eine Point Struktur wie folgt definieren:Wie definiere ich grundlegende Python-Strukturen?

(struct Point (x y) #:transparent) 

Ein Punkt ist nun eine Struktur mit zwei Feldern namens x und y. Ich kann zwei Strukturen für (tiefe) Gleichheit vergleichen, indem ich equal? rufe.

Was ist das Äquivalent in Python? Es scheint mir, wie ich zwölf Zeilen schreiben:

class Point(): 
    def __init__(self,x,y): 
     self.x = x; 
     self.y = y; 

    def __eq__(self, other): 
     return ((type(other) is Point) 
      and self.x == other.x 
      and self.y == other.y) 

    def __ne__(self, other): 
     return not(self == other) 

... aber sicher gibt es einen einfacheren Weg?

+2

nitpick, benötigen Sie einen '#: transparent' auf' struct' Definition in '#lang racket' tiefe Gleichheit zu bekommen, aber das ändert nicht die Anzahl der Zeilen, die es braucht. –

+0

@ JohnClements, Sie können einfach __eq__ und __lt__ definieren und Ihre Objekte werden mit '>,> =, lmiguelvargasf

+0

Beachten Sie, dass Ihr Python-Code Platz für viele benutzerdefinierte Verhaltensweisen bietet, von denen nicht alle für jede Klasse erforderlich sind. Außerdem mussten Sie nur zehn Zeilen schreiben. – TigerhawkT3

Antwort

6

Ja, nun, wenn Sie eine ganze Klasse benötigen, um Ihren Datentyp darzustellen, müssen Sie sich auf die __eq__ und verwandte Methoden verlassen. Doch in diesem speziellen Fall ein Pythonista verwenden würde ein namedtuple:

from collections import namedtuple 
Point = namedtuple('Point', ['x','y']) 

welche alle, die von tuple erben.

+0

Huh. Stupid StackOverflow hat mich nicht auf deine neue Antwort aufmerksam gemacht und meine Zeit mit überflüssigen Informationen verschwendet. Ich lasse es nur an seinem Platz, weil es die zusätzlichen Informationen über die Veränderlichkeit und das Verhalten der Gleichheitsprüfung enthält. – ShadowRanger

+1

@ShadowRanger yeah, du hast eine Erwähnung von mir bekommen, weil du die Warnung eingeschlossen hast, dass '(Point (1, 2) == (1, 2)' zu 'True'!) –

+0

Nice! Extra upvote für die Warnung vor dem Begriff" Dunder Methoden. "Die $ 64K Followup Frage ist, ob Lehrer in späteren Kursen alarmiert werden, dass alle meine Schüler benannte Tupel anstelle von Klassen verwenden. Vielen Dank. –

3

Wenn Sie Veränderlichkeit nicht brauchen, ist die einfachste Art und Weise grundlegende Klassen dieser Art zu machen, ist collections.namedtuple:

import collections 

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

Das ist es. Sie können einfach Point Objekte mit pt = Point(1, 2) oder ähnlichem machen, und sie funktionieren wie Zwei-Tupel, aber sie lassen Sie auch über benannte Attribute, z. pt.x, .

wird die Gleichheit Prüfung etwas lockerer sein (Point(1, 2) == (1, 2) zu True wertet, weil alle namedtuple s Subklassen von tuple und wird mit tuple Regeln, und in der Tat verschiedene Unterklassen von tuple außer Kraft nicht die Vergleichsmethoden vergleichen Vergleichen Sie einander gleich, wenn sie die gleichen Werte haben), aber vorausgesetzt, dass tuple s in der Regel als anonyme leichte "Klassen" verwendet werden, ist dies oft, was Sie wollen.

Wenn Sie ein Verhalten anpassen müssen (Hinzufügen von Funktionen oder strengere Typenvergleiche), können Sie eine benutzerdefinierte Klasse von einer namedtuple erben, um die grundlegenden Funktionen kostenlos zu erhalten, und dann die Bits anpassen, die Ihnen wichtig sind, z , zu verhindern, dass es gleich testen Point Typen an nicht, können Sie tun:

class Point(collections.namedtuple('PointBase', 'x y')): 
    def __eq__(self, other): 
     if not isinstance(other, Point): 
      return False 
     return super().__eq__(other) 

    # Sadly, tuple defines __ne__, so you must override it too to behave properly 
    # You don't need the canonical __ne__ implementation that handles NotImplemented 
    # though, since you're explicitly unfriendly to non-Point types 
    def __ne__(self, other): return not (self == other) 
+1

Ich habe den Verdacht, dass ein Racket-Programmierer Unbeweglichkeit findet, ein * Feature * zu sein :) –

+0

@ juanpa.arrivillaga: Ich hatte noch nie von Racket bis heute gehört; rein funktional nehme ich es? In diesem Fall, ja, Unveränderlichkeit ist gut. – ShadowRanger

+0

@ShadowRanger Nein, nicht rein funktional. Definitiv funktional - wenn Sie nicht einen guten Grund haben. –