繁体   English   中英

用自动递增的实例属性实现类的最Python方式是什么?

[英]What is the most Pythonic way of implementing classes with auto-incrementing instance attributes?

我有几节课。 创建实例时,期望的行为是为实例分配了ID。 为简单起见,让我们假设ID应该从0开始,并在每次创建实例时增加1。 对于这几种类别中的每一种,ID应该独立增加。

我知道如何用C ++做到这一点。 我实际上也在Python中做到了这一点,但是我不喜欢C ++解决方案,并且我想知道这是由于我对Python的了解有限(不到6周)还是有更好的解决方案? ,更Python化的方式。

在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 ++中,我有一个很好的主意,我在做什么,例如,即使我的类实际上继承了乘法(不仅仅来自Countable <>模板化类),我也看不到任何问题-一切都很简单。

现在,在Python中,我看到了以下问题:

1)当我使用组合时,我实例化了计数类:

counterClass = Countable()

我必须为每个课程都这样做,这可能容易出错。

2)当我使用继承时,当我想要繁衍时会遇到更多麻烦。 请注意,上面我没有定义Counted或AnotherCounted的__init__ ,但是如果我继承了乘法,则必须显式调用基类构造函数,或者使用super()。 我不喜欢这样(还可以吗?)我也可以使用元类,但是我的知识在那里受到限制,而且似乎增加了复杂性而不是简单性。

总而言之,尽管必须使用Countable()显式定义counterClass类属性,但我认为这种组合方式可能更适合Python实现。

感谢您对我的结论的有效性的意见。

我也希望有比我更好的解决方案的提示。

谢谢。

我会使用__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

我可能会使用一个简单的类装饰器...

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

如果您真的想以“幻想”的方式进行此操作,则可以使用元类:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM