问题
I'm coming to Python from Racket. In Racket, I would define a Point structure like this:
(struct Point (x y) #:transparent)
A point is now a structure with two fields named x and y. I can compare two structures for (deep) equality by calling equal?.
What is the equivalent in Python? It looks to me like I have to write twelve lines:
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)
... but surely there's an easier way?
回答1:
Yes, well, if you need an entire class to represent your data type, then you will have to rely on the __eq__ and related dunder methods. However, in this particular case, a Pythonista would use a namedtuple:
from collections import namedtuple
Point = namedtuple('Point', ['x','y'])
Which will inherit all that from tuple.
回答2:
If you don't need mutability, the simplest way to make basic classes of this sort is collections.namedtuple:
import collections
Point = collections.namedtuple('Point', 'x y')
That's it. You can just make Point objects with pt = Point(1, 2) or the like, and they work like two-tuples, but they also let you access them via named attributes, e.g. pt.x, pt.y.
The equality checking will be a little looser (Point(1, 2) == (1, 2) evaluates to True, because all namedtuples are subclasses of tuple and will compare using tuple rules, and in fact, different subclasses of tuple that don't override the comparison methods will compare equal to each other if they have the same values), but given that tuples are typically used as anonymous lightweight "classes", this is often what you want.
If you need to customize some behavior (adding functionality, or make the type comparisons stricter), you can make a custom class inherit from a namedtuple to get the basic features for free, then customize the bits you care about, e.g., to prevent it testing equal to non-Point types, you can do:
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)
来源:https://stackoverflow.com/questions/42287579/how-to-define-basic-python-structures