我应该在Python中实现具有常量接口的类吗?

时间:2013-08-04 14:35:28

标签: python const

我曾经在C ++中编写具有常量接口的类,并想向您寻求建议:我应该尝试在我的python程序中进行吗?

让我们假设我想拥有Point类的不可变对象。 这是C ++代码:

class Point
{
public:
    Point(double x, double y) :
        x_{x},
        y_{y}
    { }

    double x() const { return x_; }
    double y() const { return x_; }

private:
    double x_;
    double y_;
};

使用Point类型的对象我知道它们永远不会改变(我相信有一些黑客可以做到,但现在没关系)。

在python中我有几种方法。

你是偏执狂!保持简短而简单!

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

[+] 非常清晰的代码

[ - ] 无法解决问题

尝试只为类属性编写getter。

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

    def x(self):
        return self._x

    def y(self):
        return self._y

[+] 前导下划线显示该属性为“私有”

[?] 我认为编写“模仿C ++代码”并不是一个好主意。仅仅因为它是一种不同的语言。

[ - ] 属性仍然很容易访问。我应该用双下划线命名吗? (__x和__y)

还有一种方法是编写我在本主题中找到的装饰器:How to create a constant in Python

def constant(f):
    def fset(self, value):
        raise SyntaxError
    def fget(self):
        return f()
    return property(fget, fset)

class Point:
    ...
    @constant
    def x(self)
        return self.__x

[+] 完全解决问题(是的,我仍然可以更改x和y的值,但会变得更难)

[?] 这是一种蟒蛇方式吗?

[ - ] 代码过多

所以,我的问题是,最佳做法是什么?

2 个答案:

答案 0 :(得分:1)

我认为namedtuple正是您想要的:

>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(10,20)
>>> p.x
10
>>> p.y
20
>>> p.x = 100
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

答案 1 :(得分:1)

第一个很棒,如果你不需要超出namedtuple提供的功能(如果你需要一些方法,你可以创建一个子类)。

  

Namedtuple似乎不是一个解决方案,因为我不认为它提供任何类型的不变性。

这是不正确的。这是完全不可改变的。它比用户定义的类更不可变。

第二种方法确实不是很好的风格。属性比普通的getter更受欢迎。第三个使用属性,但它以非常迂回和令人困惑的方式这样做,以下代码是等效的并且更简单:

class Point:
    ...
    @property
    def x(self)
        return self._x

property的装饰器形式没有setter,因此在赋值时已经抛出异常(一种更合适的引导异常类型)。双下划线在这里是一个糟糕的选择,它们适用于预期子类化的时候。 这是我自己使用的选项,并且当namedtuple不合适时会建议。