我是从Racket来到Python的。在Racket中,我会定义一个Point
结构,如下所示:
(struct Point (x y) #:transparent)
现在,一个点是一个包含两个名为x
和y
的字段的结构。我可以通过调用equal?
来比较两个结构(深度)相等。
Python中的等价物是什么?在我看来,我必须写十二个行:
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)
...但肯定有更简单的方法吗?
答案 0 :(得分:6)
是的,如果您需要一个完整的类来表示您的数据类型,那么您将不得不依赖__eq__
和相关的dunder方法。但是,在这种特殊情况下,Pythonista将使用namedtuple
:
from collections import namedtuple
Point = namedtuple('Point', ['x','y'])
将从tuple
继承所有内容。
答案 1 :(得分:3)
如果您不需要可变性,那么制作此类基本类的最简单方法是collections.namedtuple
:
import collections
Point = collections.namedtuple('Point', 'x y')
那就是它。您可以使用Point
等制作pt = Point(1, 2)
个对象,它们的工作方式类似于两元组,但它们也允许您通过命名属性访问它们,例如pt.x
,pt.y
。
相等检查会稍微宽松一些(Point(1, 2) == (1, 2)
评估为True
,因为所有namedtuple
都是tuple
的子类,并将使用tuple
进行比较规则,事实上,如果它们具有相同的值,那么不覆盖比较方法的tuple
的不同子类将相互比较,但是通常使用tuple
s作为匿名轻量级"类",这通常是你想要的。
如果您需要自定义某些行为(添加功能或使类型比较更严格),您可以从namedtuple
继承自定义类以免费获取基本功能,然后自定义您关注的位例如,为了防止测试等于非Point
类型,您可以这样做:
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)