我有几节课。实例创建的所需行为是为实例分配ID。为简单起见,我们假设ID应从0开始,并在每次创建实例时增加1。对于这几个类中的每一个,ID应该独立递增。
我知道如何在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;
}
到作曲方式:
#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 ++中,我很清楚我在做什么,例如即使我的类实际上继承了multiply(不仅仅是来自Countable&lt;&gt;模板化类),我也没有看到任何问题 - 一切都很简单。
现在,在Python中,我看到了以下问题:
1)当我使用合成时,我实例化计数类:
counterClass = Countable()
我必须为每个班级做这个,这可能容易出错。
2)当我使用继承时,当我想要加倍时,我会遇到进一步的麻烦。注意上面,我没有定义Counted的__init__
和AnotherCounted,但是如果我继承了multiply,我必须显式地调用基类构造函数,或者使用super()。我不喜欢这个(但是?)我也可以使用元类,但我的知识有限,似乎它增加了复杂性而不是简单性。
总之,我认为组合方式对于Python实现可能更好,尽管必须使用Countable()显式定义counterClass类属性。
我很感激您对我的结论的有效性的看法。
我也很欣赏有关比我更好的解决方案的提示。
谢谢。
答案 0 :(得分:4)
我会使用__new__
,这样您就不必记得在__init__
中做任何事情了:
class Countable(object):
counter = 0
def __new__(cls, *a, **kw):
instance = super(Countable, cls).__new__(cls, *a, **kw)
instance.id = cls.counter + 1
cls.counter = instance.id
return instance
class A(Countable):
pass
class B(Countable):
pass
print A().id, A().id # 1 2
print B().id # 1
答案 1 :(得分:2)
我可能会使用一个简单的类装饰器......
import itertools
def countable(cls):
cls.counter = itertools.count()
return cls
@countable
class Foo(object):
def __init__(self):
self.ID = next(self.__class__.counter)
@countable
class Bar(Foo):
pass
f = Foo()
print f.ID
b = Bar()
print b.ID
如果你真的想这样做,那就是&#34;幻想&#34;方式,你可以使用元类:
import itertools
class Countable(type):
def __new__(cls,name,bases,dct):
dct['counter'] = itertools.count()
return super(Countable,cls).__new__(cls,name,bases,dct)
class Foo(object):
__metaclass__ = Countable
def __init__(self):
self.ID = next(self.__class__.counter)
class Bar(Foo):
pass
f = Foo()
print f.ID
b = Bar()
print b.ID