2

我曾经用 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

[+]前导下划线表示属性是“private”

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

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

另一种方法是编写我在本主题中找到的装饰器:如何在 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 的值,但它变得更难了)

[?]它是一种 python 方式吗?

[-]代码太多

所以,我的问题是,最佳实践是什么?

4

2 回答 2

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
于 2013-08-04T14:49:51.173 回答
1

第一个很好,如果您不需要namedtuple提供的功能之外的太多功能(如果您需要一些方法,您可以创建一个子类)。

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

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

第二种方式确实不是很好的风格。属性优于琐碎的吸气剂。第三个使用属性,但它以一种非常迂回和混乱的方式使用,以下代码是等效的并且更简单:

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

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

于 2013-08-04T14:53:04.070 回答