2009-07-16 2 views
14

C'è un modo in python per incrementare int oggetto sul posto, int non sembra per implementare in modo __iadd__ + = 1 in realtà restituisce un nuovo oggettoincremento int oggetto

>>> n=1 
>>> id(n) 
9788024 
>>> n+=1 
>>> id(n) 
9788012 

Quello che voglio è rimanere n che punta allo stesso oggetto.

Scopo: Ho classe derivata da int e voglio implementare tipo C '++ n' operatore per quella classe

Conclusione: ok come int è immutabile non c'è modo, sembra che io dovrò scrivere il mio classe qualcosa di simile

class Int(object): 
    def __init__(self, value): 
     self._decr = False 
     self.value = value 

    def __neg__(self): 
     if self._decr: 
      self.value -= 1 
     self._decr = not self._decr 
     return self 

    def __str__(self): 
     return str(self.value) 

    def __cmp__(self, n): 
     return cmp(self.value, n) 

    def __nonzero__(self): 
     return self.value 

n = Int(10) 
while --n: 
    print n 
+0

Perché vuoi implementare un operatore di prefisso per esso? Stai per aggiungere un preprocessore personalizzato per convertire il ++ n in una chiamata di metodo? – Ryan

+1

hmm Voglio solo mostrare al mio amico che il pitone può fare mentre --n: print n;) –

+0

vedere questo per un modo piacevole se un po 'contorto per avvolgere i tuoi in una classe anonima (che è mutevole) che si comporterà come un 'reference': http://stackoverflow.com/a/1123054/409638 ie ref = type ('',(), {'n': 1}) – robert

risposta

12

interi sono immutabili, quindi dovrete costruire la propria classe con tutti i metodi del int se volete un "int mutabile"

+5

Gli inti di quella classe rimarranno immutabili. –

+1

Non fa differenza se gli int di classe sono immutabili, il valore dell'attributo è variabile, quindi è possibile definire una classe 'MutableInt' funzionante, non quella che si vorrebbe mai. –

+0

Ho fatto questo: https://github.com/markrages/python_mutable_number – markrages

3

probabilmente sarebbe più facile creare una classe che implementa i metodi int e avvolge un intero interna.

+1

Non solo più semplice, ma potrebbe essere l'unico modo in cui gli int sono non mutabile – Arkady

0

Sì, la risposta breve è che, int sono immutabili.

3

Se si deve assolutamente far funzionare quel codice, ecco un metodo sporco, in cui un metodo di istanza si sposta su una cornice e sovrascrive la propria voce di locals. Non lo consiglierei. (come, davvero no. Non sono nemmeno sicuro di cosa faccia. Cosa succede alla vecchia istanza? Non ne so abbastanza dei frame ...). Davvero, sto solo postando questo perché tutti hanno detto che è impossibile, quando in realtà è solo una forma ridicolmente cattiva. ;-)

import sys 
class FakeInt(int): 
    def __init__(self, *arg, **kwarg): 
     self._decr = False 
     int.__init__(self, *arg, **kwarg) 
    def __neg__(self): 
     if self._decr: 

      upLocals = sys._getframe(1).f_locals 
      keys, values = zip(*upLocals.items()) 
      i = list(values).index(self) 

      result = FakeInt(self-1) 
      upLocals[keys[i]]=result 

      return result 
     self._decr = not self._decr 
     return self 

A = FakeInt(10) 
while --A: 
    print A, 

uscite:

9 8 7 6 5 4 3 2 1 
+0

su una nota non correlata, qualcuno sa se è possibile trovare l'indice di un elemento in una tupla senza convertirlo prima in una lista? i = list (valori) .index (self) sembra un po 'tondo. – Markus

+2

+1 interessante, ma sì, avrei paura di usare questo –

+0

@Markus a = (1,2,3,4,5); a.index (3) risulta in 2. Almeno questo è con python 3 –

2

È possibile inserire un oggetto immutabile all'interno di un contenitore mutevole; le liste sono più facili.

stampe questo codice 0, dimostrando il problema:

a = 0  # `a` points to a new int (a `0`) 
b = a  # `b` points to the same thing as `a` (the `0`) 
b = 1  # `b` points to a new int (a `1`) 
print(a) # `a` still points to the same thing (the `0`) 

Se si mette l'int in un elenco, ma per il resto utilizza lo stesso codice di prima, è possibile ottenere l'effetto di avere un int mutabile (anche se è l'elenco che viene mutato in realtà):

a = [0]  # `a` points to a new `0` inside a new list 
b = a   # `b` points to the same thing as `a` (the list) 
b[0] = 1  # the list that `a` and `b` point to is mutated 
print(a[0]) # `a[0]` points to the same object as `b[0]` (the `1`) 

In pratica, si dovrebbe strutturare i dati in modo che quanto sopra 'trucco' è ridondante. Gli esempi non dovrebbero essere usati direttamente, ma dovrebbero aiutarti a capire cosa fare.

4

È possibile utilizzare i ctypes come numeri interi mutabili. La scelta del tipo corretto sarà comunque importante, poiché limitano la dimensione del numero intero che possono trasportare.

>>> from ctypes import c_int64 
>>> num = c_int64(0) 
>>> id(num) 
4447709232 
>>> def increment(number): 
...  number.value += 1 
... 
>>> increment(num) 
>>> increment(num) 
>>> increment(num) 
>>> num.value 
3 
>>> id(num) 
4447709232 
>>> 

Maggiori informazioni: https://docs.python.org/2/library/ctypes.html#fundamental-data-types

+0

Per la registrazione, questo è più lento dell'incremento di un numero intero normale. – Zaz

+0

Probabilmente è una cattiva idea per diversi motivi, ma grazie comunque, ora so cosa è necessario importare come 'mutable_int'. – Daerdemandt

0

Ho avuto un problema simile oggi e si avvicinò con una classe chiamata IterInt che consente di aumentare o diminuire in posizione con "+" e - decoratori "".

Usage:

x = IterInt() 

print x 
# result: 0 

print +x 
# result: 1 

print +x 
# result: 2 

print +x 
# result: 3 

print -x 
# result: 2 

print -x 
# result: 1 

print -x 
# result: 0 

Nel mio caso ho avuto una situazione in cui ho voluto modificare menu esistente di un'applicazione con l'inserimento di diversi elementi di comando dopo un indice specifico.L'API fornita che sto usando ha una funzione "addCommand" che può prendere un indice al quale inserire.

Considerate questo pseudo codice in cui menu ha comandi di un bel passaggio g, qualcosa come menù = [a, f, g], e voglio inserire essere indice 1-4

idx = 1 
menu.addCommand(b, index=idx) 
idx += 1 
menu.addCommand(c, index=idx) 
idx += 1 
menu.addCommand(d, index=idx) 
idx += 1 
menu.addCommand(e, index=idx) 
idx += 1 

# result: menu = [a, b, c, d, e, f] 

Sarebbe bello se potessi scrivere così incrementi di idx in luogo come c dove potrei fare idx ++, ma le funzioni non permettono la metodologia idx + = 1 di Python negli argomenti.

Soluzione:

class IterInt(int): 
""" 
This function will return the next integer from the init_value starting point or 0 if None. 
Each subsequent call to increment returns the next value 
:param init_value: 
:return: 
""" 
def __init__(self, init_value=None): 
    if init_value is None: 
     init_value = 0 

    if init_value is not None: 
     self.increment_value = init_value 
    self.increment_value = init_value 

def __pos__(self): 
    self.increment_value += 1 
    return self.increment_value 

def __neg__(self): 
    self.increment_value -= 1 
    return self.increment_value 


idx = IterInt(1) 
menu.addCommand(b, index=+idx) 
menu.addCommand(c, index=+idx) 
menu.addCommand(d, index=+idx) 
menu.addCommand(e, index=+idx) 

# result: menu = [a, b, c, d, e, f]