为类的实例分配ID(Pythonic)

0 投票
3 回答
1334 浏览
提问于 2025-04-15 23:39

我想让某个类的每个实例都有一个独特的整数标识符,这个标识符是根据我创建它们的顺序来的,从0开始。比如在Java中,我可以用一个静态类变量来实现这个功能。我知道在Python中也可以模拟这种行为,但最“Pythonic”的做法是什么呢?

谢谢

3 个回答

0

我想问一个好问题,那就是它们是什么时候以及怎么被创建的?如果你只是想在某个时间点创建一定数量的它们,那就可以在一个循环里用范围来做。

class A:
    def __init__ (self, id):
        self.id = id
        //do other stuff

class_list = []
for i in xrange(10):
    class_list.append(A(i))

这是一种很符合Python风格的方法。如果你是根据需要随时创建它们,那我觉得唯一的方法就是在某个地方保持一个静态的ID变量。不过,我不太确定你是怎么创建它们的。

补充一下:哦,如果不确定的话,输入“import this”总能帮你找到一些关于什么是“Python风格”的线索;)

1

the-myyn的回答很好——我觉得把计数器放在类对象里是个不错的主意。不过要注意,按照现在的写法,它并不是线程安全的。

所以可以把它放在一个类方法里,并使用锁来保护:

import threading

class CounterExample(object):

    _next_id = 0
    _id_lock = threading.RLock()

    @classmethod
    def _new_id(cls):
        with cls._id_lock:
            new_id = cls._next_id
            cls._next_id += 1
        return new_id

    def __init__(self):
        self.id = self._new_id()

def test():
    def make_some(n=1000):
        for i in range(n):
            c = CounterExample()
            print "Thread %s; %s has id %i" % (threading.current_thread(), c, c.id)

    for i in range(10):
        newthread = threading.Thread(target=make_some)
        newthread.start()

test()

这个代码会运行10个线程,每个线程创建1000个实例。如果你不加锁直接运行,最后的id很可能会小于9999,这就说明出现了竞争条件。

3

以下的方法可以算是比较“python风格”的(这是我个人对python风格的理解——既清晰又简洁):

class CounterExample(object):

    instances_created = 0

    def __init__(self):
        CounterExample.instances_created += 1

    def __del__(self):
        """ If you want to track the current number of instances
            you can add a hook in __del__. Otherwise use
            __init__ and just count up.
        """
        CounterExample.instances_created -= 1

如果你需要处理很多类,并且这些类都需要那种属性,你也可以考虑为它们写一个元类。

这里有一个元类的例子:http://www.youtube.com/watch?v=E_kZDvwofHY#t=0h56m10s

撰写回答