如何定义基本的Python结构?

时间:2017-02-17 01:03:04

标签: python racket

我是从Racket来到Python的。在Racket中,我会定义一个Point结构,如下所示:

(struct Point (x y) #:transparent)

现在,一个点是一个包含两个名为xy的字段的结构。我可以通过调用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)

...但肯定有更简单的方法吗?

2 个答案:

答案 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.xpt.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)