Per un auto-progetto, ho voluto fare qualcosa di simile:Il tentativo di replicare stringa funzionalità internato di Python per i non-stringhe
class Species(object): # immutable.
def __init__(self, id):
# ... (using id to obtain height and other data from file)
def height(self):
# ...
class Animal(object): # mutable.
def __init__(self, nickname, species_id):
self.nickname = nickname
self.species = Species(id)
def height(self):
return self.species.height()
Come potete vedere, non ho davvero bisogno di più di un'istanza di Species (id) per id, ma ne creerei uno ogni volta che creo un oggetto Animal con quell'id, e probabilmente avrei bisogno di più chiamate, per esempio, Animal(somename, 3)
.
Per risolvere questo, quello che sto cercando di fare è di fare una classe in modo che per 2 istanze di esso, diciamo A e B, il seguente è sempre vero:
(a == b) == (a is b)
Questo è qualcosa che Python fa con stringhe letterali e si chiama stage. Esempio:
a = "hello"
b = "hello"
print(a is b)
che stampa produrrà vero (a patto che la stringa è abbastanza breve se stiamo usando direttamente la shell Python).
Posso solo immaginare come CPython faccia questo (probabilmente implica un po 'di magia C), quindi sto facendo la mia versione di esso. Finora ho:
class MyClass(object):
myHash = {} # This replicates the intern pool.
def __new__(cls, n): # The default new method returns a new instance
if n in MyClass.myHash:
return MyClass.myHash[n]
self = super(MyClass, cls).__new__(cls)
self.__init(n)
MyClass.myHash[n] = self
return self
# as pointed out on an answer, it's better to avoid initializating the instance
# with __init__, as that one's called even when returning an old instance.
def __init(self, n):
self.n = n
a = MyClass(2)
b = MyClass(2)
print a is b # <<< True
Le mie domande sono:
a) è il mio problema nemmeno la pena di risolvere? Dal momento che il mio oggetto Species previsto dovrebbe essere abbastanza leggero e il numero massimo di volte che Animal può essere chiamato, piuttosto limitato (immagina un gioco Pokemon: non più di 1000 istanze, top)
b) Se lo è, è questo un approccio valido per risolvere il mio problema?
c) Se non è valido, potresti approfondire un modo più semplice/più pulito/più Pythonic per risolvere questo problema?
potete vedere una molto simile sorta di codice in esecuzione di Python di i vari ['wrapper's per' functools.lru_cache'] (https://hg.python.org/cpython/file/3.5/Lib/functools.py#l453). Come succede, non si bloccano per le operazioni "atomiche" quando il lavoro svolto è atomico, che supporta il mio commento sopra, ma usano lo stesso "prova a ottenere dalla cache con il blocco, se non è riuscito, rilascia il blocco, eseguire costoso lavoro, riacquisti il blocco e aggiorna la cache se non viene eseguito "il pattern che ho usato sopra per la dimensione della cache è limitato (e i gruppi di operazioni devono essere eseguiti atomicamente). – ShadowRanger