2010-06-07 3 views
0

Я хочу, чтобы каждый экземпляр некоторого класса имел уникальный целочисленный идентификатор, основанный на том, что я их создаю, начиная с (скажем) 0. На Java я мог бы сделать это с переменной статического класса. Я знаю, что я могу эмулировать такое же поведение с Python, но какой был бы самый «Pythonic» способ сделать это?Назначение идентификаторов экземплярам класса (Pythonic)

Благодаря

ответ

3

Следующий подход будет относительно вещий (для моего субъективного суждения вещий - явный, еще краткое):

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.

+1

Возможно, вы также захотите поместить 'self.identifier = CounterExample.instances_created' в тело' __init__', поскольку, похоже, mellort хочет иметь каждый объект с уникальным идентификатором. (Это, в свою очередь, означает, что вы не захотите уменьшать 'instance_created' во время удаления, поскольку это может привести к тому, что объекты будут инициализированы позже, имея неидентичные идентификаторы.) – JAB

+0

Это работает отлично, пока вы не попытаетесь сделать это с помощью внутренний класс, после чего он терпит неудачу с «CounterExample не определено». Есть ли что-то еще, что вам нужно сделать, чтобы он работал с внутренним классом? – Zxaos

0

Я думаю, хороший вопрос, когда и как они создаются? Если вы просто создаете определенное количество из них в один момент времени, используйте диапазон в цикле for.

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

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

Это был бы один питонический путь. Если вы создаете их, когда вам это нужно, я думаю, что единственный способ - сохранить старую переменную id. Хотя я не уверен, как вы их делаете.

EDIT: Ой, а также, в случае сомнений «импорт этого» всегда может помочь вам на правильный путь для выяснения того, что «вещий»;)

1

ответа-myyn это хорошо - я думаю, объект класса - это прекрасное место, чтобы спрятать счетчик. Тем не менее, обратите внимание, что, как написано, оно не является потокобезопасным. Так завернуть его в classmethod, который использует блокировку:

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 экземпляров каждый. Если вы запустите его без кода блокировки, вы, скорее всего, получите последний идентификатор ниже 9999, демонстрируя состояние гонки.

Смежные вопросы