c++ - 实现具有自动递增实例属性的类的最 Pythonic 方式是什么?

标签 c++ python inheritance composition

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

我知道如何在 C++ 中执行此操作。我实际上也用 Python 做过,但我不像 C++ 解决方案那样喜欢它,我想知道这是否是由于我对 Python 的了解有限(仅 6 周多一点),或者是否有更好的,更 Pythonic 的方式。

在 C++ 中,我使用继承和组合实现了这一点。两种实现都使用 Curiously Recurring Template Pattern (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<> 模板化类),我也没有看到任何问题——一切都非常简单。

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

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

counterClass = Countable()

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

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

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

如果您对我的结论的有效性提出意见,我将不胜感激。

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

谢谢。

最佳答案

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

关于c++ - 实现具有自动递增实例属性的类的最 Pythonic 方式是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17173149/

相关文章:

使用指向同一类对象的指针的 C++ 类构造函数

python - uwsgi+nginx 后面的 Django 无法设置 cookie

python - Pyspark:解析一列 json 字符串

Scala:如何两次继承相同的特征?

c++ - 如何在 C++ 中的派生类的构造函数中初始化基类的 const 变量?

java - 遍历节点类被另一个类继承的树

C++ SDL 程序立即终止

c++ - 将文本绘制到屏幕

c++ - 循环输入数据

python - django.db.utils.operationalError : (2059 ,"Authentication Plugin ' caching_sha2_password'")