2010-06-07 6 views
0

Je souhaite que chaque instance de classe ait un identificateur d'entier unique basé sur l'ordre dans lequel je les crée, en commençant par (disons) 0. En Java, je pourrais le faire avec une variable de classe statique. Je sais que je peux émuler le même genre de comportement avec Python, mais quelle serait la façon la plus «pythonique» de faire cela?Affectation d'ID aux instances d'une classe (Pythonic)

Merci

Répondre

3

L'approche suivante serait relativement pythonique (pour mon jugement subjectif de pythonique - explicite, mais concis):

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 

Si vous êtes face à un grand nombre de classes, qui besoin de ce type d'attribut, vous pouvez également envisager d'écrire une métaclasse pour cela.

Un exemple de métaclasse: http://www.youtube.com/watch?v=E_kZDvwofHY#t=0h56m10s.

+1

Vous pouvez également mettre 'self.identifier = CounterExample.instances_created' dans le corps de' __init__', car mellort semble vouloir avoir chaque objet avec un identifiant unique. (Cela signifierait, à son tour, que vous ne voudriez pas décrémenter 'instances_created' pendant la suppression, car cela pourrait potentiellement aboutir à des objets initialisés ayant des identifiants non-uniques plus tard.) – JAB

+0

Cela fonctionne bien jusqu'à ce que vous essayiez de le faire avec classe interne, à quel point il échoue avec "CounterExample n'est pas défini". Y a-t-il autre chose que vous devez faire pour le faire fonctionner avec une classe interne? – Zxaos

0

Je suppose qu'une bonne question est quand et comment sont-ils créés? Si vous créez juste un certain nombre d'entre eux à un moment donné, utilisez une plage dans une boucle 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)) 

Ce serait une façon pythonique. Si vous les faites quand vous en avez besoin, je pense que le seul moyen est de garder une variable statique id quelque part. Bien que je ne sois pas sûr de comment tu les fais.

EDIT: Oh, « cette importation » peut toujours vous aider aussi, en cas de doute sur la bonne voie pour déterminer ce qui est « pythonique »)

1

réponse de la myyn est bon - je pense l'objet de classe est un endroit parfait pour ranger le comptoir. Cependant, notez que, tel qu'il est écrit, il n'est pas sûr pour les threads. enveloppez donc dans un classmethod qui utilise un verrou:

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

Cela va 10 fils de discussion créant 1000 cas chacun. Si vous l'exécutez sans le code de verrouillage, vous risquez de vous retrouver avec le dernier identifiant inférieur à 9999, ce qui indique la condition de concurrence.

Questions connexes