2009-06-25 24 views
13

Chciałbym stworzyć niepowtarzalny identyfikator dla każdego obiektu utworzonego - tutaj jest klasa:Jak utworzyć przyrostową identyfikator klasy Pythona

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

chciałbym mieć self.ID że auto zwiększa każdym razem tworzyć nowe odniesienie do klasy, takie jak:

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

wiem, że mogę odwołać resource_cl, ale nie jestem pewien, jak postępować stamtąd ...

Odpowiedz

3

Czy jesteś świadomy id function w Pythonie i czy możesz go użyć zamiast swojego pomysłu licznika?

class C(): pass 

x = C() 
y = C() 
print(id(x), id(y)) #(4400352, 16982704) 
+1

Użyłem id (self) w klasie - wydaje się być prawo rozwiązanie dla moich potrzeb - dziękuję – meade

+8

Pamiętaj, że wartości zwrócone przez id() nie gwarantują, że będą unikatowe w ramach jednego wykonania programu (mogą być ponownie wykorzystane, gdy zbierane są obiekty). Nie mają też gwarancji, że podążają za jakimś konkretnym wzorcem (pierwotnie prosiłeś o autodopasowanie). –

+0

R. Pate: absolutnie poprawne i ważne, o czym należy pamiętać; Chciałem tylko upewnić się, że był on świadomy istnienia funkcji id i ocenić ją poprawnie, zanim zdecyduję się zrobić coś ręcznie. – llimllib

12

pierwsze, należy wielkimi literami Nazwy dla Classe s. małe litery atrybutów.

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 
+2

Wewnątrz __init__, odwołanie do klasy class_counter jest własnością klasy. Powinno to wyglądać tak: Resource.class_counter + = 1 –

+0

S.Lott, spróbowałem. W przypadku pierwszej wersji każdy obiekt będzie miał identyfikator 0, a rachunek klasy 1. –

+2

będzie działał w przypadku uzyskania dostępu do wartości. A więc: self.id = self.class_counter Będzie działać zgodnie z oczekiwaniami, ponieważ rozdzielczość atrybutu zostanie przywrócona do właściwości klasy. Nie jest tak w przypadku ustawiania atrybutu, ponieważ zestaw wartości znajdzie się w zakresie instancji, a nie w klasie bazowej. –

10

Korzystanie liczyć z itertools jest dobre dla tego:

>>> 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 

Ten sam interfejs działa, jeśli później trzeba zmienić sposób wartości są generowane, wystarczy zmienić definicję id_generator.

38

zwięzły i elegancki:

import itertools 

class resource_cl(): 
    newid = itertools.count().next 
    def __init__(self): 
     self.id = resource_cl.newid() 
     ... 
+1

+1: Jest to jedyny niezawodny i bezpieczny dla wątków sposób robienia tego wśród wszystkich obecnych odpowiedzi. 'id' może zwracać nieunikalne wartości, a po prostu zwiększanie zmiennej klasy wewnątrz' __init__' może prowadzić do warunków wyścigu. Podoba mi się również pomysł przechowywania odwołania do 'count(). Next' zamiast bezpośredniego przechowywania wyniku' count() '. –

+0

Zdarza się, że ten sam obiekt używa identyfikatora(), np. a = "123" b = "123" id (a) == id (b) – clsung

+0

@clsung Ciągi w języku Python są "internowane" i nie można ich modyfikować. "123" jest tym samym obiektem podczas sesji Pythona. "a" i "b" są nazwane referencjami, a nie "obiektami" lub "instancjami" "123". W tym przypadku wskazują na internowany ciąg znaków. Google python intern dla więcej informacji. – DevPlayer

0

Inna uwaga na id() i przemyślenia nawzajem odpowiedź na jego temat. id() może zwrócić unikalny numer, wtedy i tylko wtedy, gdy zapamiętuje każdy identyfikator, który kiedykolwiek został zwrócony, nawet jeśli obiekt został usunięty; które to (id()) nie robi. Tak więc ...

Na poparcie tego, co inni mówili, że id() nie zwraca unikalnego numeru; To prawda, że ​​nie może zagwarantować unikalnej wartości wtedy i tylko wtedy, gdy przechowujesz te wartości id() jako odniesienia do obiektów ORAZ że usuwasz wystąpienia obiektów, dla których otrzymujesz id(). ALE ! użycie id() jako odwołania oznacza, że ​​zasadniczo masz obiekt, który ma jakiś klucz połączony w jakiś sposób z innym obiektem.

Nie jest to unieważniane przez nieunikalność id(). Jest on unieważniany tylko wtedy, gdy nie sprawdzasz, czy dodanie nowego obiektu ma istniejący wcześniej identyfikator() już zapisany jako odniesienie do innej instancji obiektu.

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 

BUT storeit [4357891223] zwraca pewną inną instancję obiektu, nie object3; dlatego link> < pozostaje ważny, ale niepowtarzalność się nie udaje.

0

Lubię używać generatorów dla ids. Pozwól generatorowi zachować listę identyfikatorów, które są już używane.

# [email protected] 
# 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 

Chociaż nie jest to wydajna pamięć dla ogromnych zbiorów danych w pamięci. Jeśli chcesz użyć czegoś takiego, zmodyfikuj to, aby system operacyjny obsługiwał buforowanie do pliku ... powiedzmy przez nazwaną potokę.

1

Identyfikatory czasem korzystają z niektórych pól obiektu, który chciałbyś przywołać. Jest to technika bazująca na starym stylu.

na przykład, jeśli masz aplikację, która prowadzi dokumentację dla połączeń przychodzących klienta, wówczas możliwe zastosowania identyfikator generowany przez czas = niektóre rzeczy jeszcze

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

beaware tylko time.time() i czasu. clock() są wartością zwracaną przez komputer, chyba że są generowane na serwerze. A jeśli na serwerze upewnij się, że zegar serwera jest ustawiony prawidłowo; jak zawsze.

Powiązane problemy