我曾经在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的值,但会变得更难)
[?] 这是一种蟒蛇方式吗?
[ - ] 代码过多
所以,我的问题是,最佳做法是什么?
答案 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不合适时会建议。