2013-08-04 56 views
2

我曾經用C++編寫帶有常量接口的類,並且想問你一些建議:我應該試着在我的python程序中做到這一點嗎?我應該用Python中的常量接口實現類嗎?

讓我們假設我想擁有類Point的不可變對象。 這裏是C++代碼:Point類型的

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_; 
}; 

使用對象我知道,他們永遠不會改變(我相信有一些黑客做到這一點,但現在沒關係)。

在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,但它變得更難)

[?]它是一種Python方式嗎?

[ - ]太多的代碼

所以,我的問題是,什麼是最好的做法是什麼?

+4

爲什麼'namedtuple'類沒有解決問題?請注意,雙下劃線名稱是* not * private,只是模糊不清。他們的目標是在基類和它的子類之間創建一個名稱空間,而不是隱私。 –

+1

'const'的最初目標是優化;編譯器可以確定該對象是不可變的,從而使某些速度快捷方式成爲可能。 Python不提供這樣的優化*無論如何*,爲什麼所有的麻煩? –

+1

@MartijnPieters C++中'const'的最初目標可能是優化,但更一般的不變性概念非常有用,即使可能會降低性能,人們也很容易介紹它。 – delnan

回答

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 
+0

這是我的錯:我確定它不會拋出異常,我必須檢查它。謝謝。 – Unforgiven

+0

List =可變,元組=不可變。這就是爲什麼你可以使用一個元組(或稱爲「元組」)作爲字典鍵或集合元素,但是你不能使用列表。 – PaulMcG

1

首先是巨大的,如果你不需要超出namedtuple提供了很多功能(如果你需要一些方法,你可以創建一個子類)。

Namedtuple似乎不是一個解決方案,因爲我認爲它不提供任何形式的不變性。

這是不正確的,因爲它得到。它是完全不可變的。它比用戶定義的類更加不可變。

第二種方法確實不是很好的風格。屬性比平凡的getter更受歡迎。第三個使用性能,但是它很婉轉和混亂的方式這樣做,下面的代碼是等價的更簡單:

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

property的裝飾形式沒有二傳手,因此已經拋出後分配異常(一個更合適的異常類型來引導)。雙下劃線在這裏是一個不好的選擇,它們是在預計子類化時使用的。 這是我使用我自己的選項,並會在namedtuple不適當時推薦。

相關問題