Как создать инкрементный идентификатор в классе Python - PullRequest
22 голосов
/ 25 июня 2009

Я хотел бы создать уникальный идентификатор для каждого объекта, который я создал - вот класс:

class resource_cl :
    def __init__(self, Name, Position, Type, Active):
        self.Name = Name
        self.Position = Position
        self.Type = Type
        self.Active = Active

Я хотел бы иметь self.ID, который автоматически увеличивается каждый раз, когда я создаю новую ссылку на класс, например:

resources = []
resources.append(resource_cl('Sam Sneed', 'Programmer', 'full time', True))

Я знаю, что могу сослаться на resource_cl, но я не уверен, что делать дальше ...

Ответы [ 8 ]

50 голосов
/ 25 июня 2009

Лаконично и элегантно:

import itertools

class resource_cl():
    newid = itertools.count().next
    def __init__(self):
        self.id = resource_cl.newid()
        ...
17 голосов
/ 25 июня 2009

Во-первых, используйте заглавные имена для классов. строчные имена для атрибутов.

class Resource( object ):
    class_counter= 0
    def __init__(self, name, position, type, active):
        self.name = name
        self.position = position
        self.type = type
        self.active = active
        self.id= Resource.class_counter
        Resource.class_counter += 1
15 голосов
/ 25 июня 2009

Использование отсчета от itertools отлично подходит для этого:

>>> import itertools
>>> counter = itertools.count()
>>> a = next(counter)
>>> print a
0
>>> print next(counter)
1
>>> print next(counter)
2
>>> class A(object):
...   id_generator = itertools.count(100) # first generated is 100
...   def __init__(self):
...     self.id = next(self.id_generator)
>>> objs = [A(), A()]
>>> print objs[0].id, objs[1].id
100 101
>>> print next(counter) # each instance is independent
3

Тот же интерфейс работает, если вам позже потребуется изменить способ генерирования значений, вы просто измените определение id_generator.

6 голосов
/ 25 июня 2009

Вам известна функция id в python, и не могли бы вы использовать ее вместо своей идеи счетчика?

class C(): pass

x = C()
y = C()
print(id(x), id(y))    #(4400352, 16982704)
3 голосов
/ 23 января 2019

Попытка ответа с наибольшим количеством голосов в Python 3 приведет к ошибке, так как .next() было удалено.

Вместо этого вы можете сделать следующее:

import itertools

class BarFoo:

    id_iter = itertools.count()

    def __init__(self):
        # Either:
        self.id = next(BarFoo.id_iter)

        # Or
        self.id = next(self.id_iter)
        ...
1 голос
/ 18 июля 2012

Идентификаторы иногда выигрывают от использования некоторых полей объекта, на который вы хотите сослаться. Это техника базы данных старого стиля.

например, если у вас есть приложение, которое ведет учет входящих телефонных звонков клиента, то возможно использовать идентификатор, сгенерированный по времени = что-то еще

ident = '%s:%.4s:%.9s' % ( time.time(), time.clock(), agent.name )
# don't forget to time.clock() once to initialize it

только остерегайтесь того, что time.time () и time.clock () являются возвращаемыми значениями для отдельного компьютера, если они не генерируются на сервере. И если на сервере убедитесь, что часы вашего сервера установлены правильно; как всегда.

0 голосов
/ 18 июля 2012

Мне нравится использовать генераторы для идентификаторов. Разрешить генератору вести список уже использованных идентификаторов.

# devplayer@gmail.com
# 2012-07(jul)-19


class MakeUniqueStr(object):
    '''
    unqstr = MakeUniqueStr(default_name='widget', sep='_')
    print(repr(unqstr('window')))
    print(repr(unqstr('window')))
    print(repr(unqstr('window')))
    print(repr(unqstr('hello')))
    print(repr(unqstr('hello')))
    print(repr(unqstr('window')))
    print(repr(unqstr('hello')))

    'window'
    'window_00000'
    'window_00001'
    'hello'
    'hello_00000'
    'window_00002'
    'hello_00001'
    '''

    def __init__(self, default_name='default', sep='_'):
        self.default_name = default_name
        self.last_base_name = default_name
        self.sep = sep

        self.used_names = []

        self.generator = self.Generator()
        self.generator.next() # initialize

    def __call__(self, name=None):
        if name <> None: self.last_base_name = name
        return self.generator.send(self.last_base_name)

    def _MakeName(self, name, index=1):
        '''_MakeName is called by the Generator. 

        Generator will always have a name and an index to pass to _MakeName. 
        Over ride this method to customize it.'''

        return name + self.sep + '%0.5d' % index

    def Generator(self):
        try_name = yield 'ready' # initialize
        index = 0
        while 1:

            if try_name not in self.used_names:
                self.used_names.append( try_name )
                sent_name = yield try_name
                try_name = sent_name
                continue

            try_name = self._MakeName( sent_name, index )
            while try_name in self.used_names:
                index += 1
                try_name = self._MakeName( sent_name, index )

            index = 0

Хотя это не эффективный способ памяти для огромных наборов данных в памяти. Если вы хотите использовать что-то подобное, измените это так, чтобы ОС обрабатывала кэширование в файл ... скажем, через именованный канал.

0 голосов
/ 18 июля 2012

Еще одна заметка об id () и переосмысление чужого ответа об этом. id () может возвращать уникальный номер, если и только если он запоминает каждый когда-либо возвращенный идентификатор, даже если объект удален; чего он (id ()) не делает. Итак, поэтому ...

В подтверждение того, что говорили другие, id () не возвращает уникальный номер; Это правда, что он не может гарантировать уникальное значение тогда и только тогда, когда вы храните эти значения id () в качестве ссылок на объекты И для которых вы удаляете экземпляры объектов, для которых вы получаете id (). НО ! использование id () в качестве ссылки означает, что у вас в основном есть объект, ключ которого каким-то образом связан с другим объектом.

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

storeit = {}

object1 = object()
print id(object1)
4357891223

storeit[ id(object1) ] = object1

object2 = object()
print id(object2)
9834923411

storeit[ id(object2) ] = object2

storeit[ id(object1) ] = object()
del object1

object3 = object()
print id(object3)
# after some 2 gigawatt tries magically i got
4357891223
# the same id as object1 had

НО storeit [4357891223] возвращает некоторый другой экземпляр объекта, а не object3; поэтому <ссылка> остается действительной, но уникальность не срабатывает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...