我有幾個班。創建實例所需的行爲是爲實例分配一個ID。爲了簡單起見,讓我們假設ID應該從0開始,並在創建每個實例時增加1。對於這幾個類中的每一個,都應該獨立地增加ID。使用自動遞增實例屬性實現類的最Python方式是什麼?
我知道如何在C++中做到這一點。我實際上也是用Python做的,但我不喜歡C++解決方案,我想知道是否是由於我對Python的瞭解有限(超過6周),或者是否有更好的方法,更多的Pythonic方式。
在C++中,我已經實現了這兩個使用繼承,並使用組合。兩種實現都使用「好奇循環模板模式」(CRPT)慣用語。我微微喜歡的繼承方式:
#include <iostream>
template<class T>
class Countable{
static int counter;
public:
int id;
Countable() : id(counter++){}
};
template<class T>
int Countable<T>::counter = 0;
class Counted : public Countable<Counted>{};
class AnotherCounted: public Countable<AnotherCounted>{};
int main(){
Counted element0;
Counted element1;
Counted element2;
AnotherCounted another_element0;
std::cout << "This should be 2, and actually is: " << element2.id << std::endl;
std::cout << "This should be 0, and actually is: " << another_element0.id << std::endl;
}
到composion方式:現在
#include <iostream>
template<class T>
class Countable{
static int counter;
public:
int id;
Countable() : id(counter++){}
};
template<class T>
int Countable<T>::counter = 0;
class Counted{
public:
Countable<Counted> counterObject;
};
class AnotherCounted{
public:
Countable<AnotherCounted> counterObject;
};
int main(){
Counted element0;
Counted element1;
Counted element2;
AnotherCounted another_element0;
std::cout << "This should be 2, and actually is: " << element2.counterObject.id << std::endl;
std::cout << "This should be 0, and actually is: " << another_element0.counterObject.id << std::endl;
}
,在Python中,沒有模板,這將使我爲每一類不同的計數器。因此,我包可數類的功能,並取得了以下實現:(繼承的方式)
def Countable():
class _Countable:
counter = 0
def __init__(self):
self.id = _Countable.counter
_Countable.counter += 1
return _Countable
class Counted (Countable()) :
pass
class AnotherCounted(Countable()):
pass
element0 = Counted()
element1 = Counted()
element2 = Counted()
another_element0 = AnotherCounted()
print "This should be 2, and actually is:", element2.id
print "This should be 0, and actually is:", another_element0.id
和組成方式:
def Countable():
class _Countable:
counter = 0
def __init__(self):
self.id = _Countable.counter
_Countable.counter += 1
return _Countable
class Counted (Countable()) :
counterClass = Countable()
def __init__(self):
self.counterObject = Counted.counterClass()
class AnotherCounted(Countable()):
counterClass = Countable()
def __init__(self):
self.counterObject = self.counterClass()
element0 = Counted()
element1 = Counted()
element2 = Counted()
another_element0 = AnotherCounted()
print "This should be 2, and actually is:", element2.counterObject.id
print "This should be 0, and actually is:", another_element0.counterObject.id
什麼困擾我是這樣的。在C++中,我有一個好主意,我在做什麼,例如即使我的類實際上繼承了繁殖(不僅來自Countable <>模板類),我看不出任何問題 - 一切都非常簡單。
現在,在Python中,我看到了以下問題:
1)當我用的組合物,我實例計數類這樣的:
counterClass = Countable()
我必須爲每一個類做到這一點,這可能很容易出錯。 2)當我使用繼承時,當我想要ihnerit繁殖時,我會遇到更多麻煩。請注意,上面我沒有定義Counsed或AnotherCounted的__init__
,但是如果我繼承了multiply,我將不得不顯式調用基類構造函數,或者使用super()。我不喜歡這個(但?)我也可以使用元類,但是我的知識僅限於此,它似乎增加了複雜性而不是簡單性。
總而言之,儘管必須使用Countable()明確定義counterClass類屬性,但我認爲組合方式對於Python實現可能更好。
我希望你對我的結論的有效性發表意見。
我也很欣賞關於比我更好的解決方案的提示。
謝謝。
美麗的解決方案。感謝您的分享。我學到了一些新東西和有用的東西。 – ondrejdee
想一想,這可以工作,因爲'計數器'(它是一個int)的不變性。順便說一句,似乎可以不使用'__new__'而是使用'__init __(self)'並將計數器稱爲'type(self).counter'來獲得相同的行爲。我現在想知道的是:我怎麼能解決類似的問題,但現在'counter'是一個列表,它應該由一個元素1添加,以便上面的代碼在第一個對象創建後產生[],[1]在第二個,[1,1]在第三等之後? – ondrejdee
如果你使用'__init__',你必須記得在子類中調用'super().__ init__'。你真的需要這樣一個列表,是在'[1] * self.id'太慢的時候按需求創建的嗎?第一次創建之前應該列出什麼? –