2015-07-23 20 views
5

Si consideri il seguente codice:Add attributo classe Python

class Foo(): 

    pass 


Foo.entries = dict() 


a = Foo() 
a.entries['1'] = 1 

b = Foo() 
b.entries['3'] = 3 

print(a.entries) 

questo stampa:

{'1': 1, '3': 3} 

perché le voci si aggiunge come attributo statico. Esiste un modo per applicare patch alla definizione della classe per aggiungere nuovi attributi (senza utilizzare l'ereditarietà).

sono riuscito a trovare il modo seguente ma sembra contorto a me:

def patch_me(target, field, value): 
    def func(self): 
     if not hasattr(self, '__' + field): 
      setattr(self, '__' + field, value()) 
     return getattr(self, '__' + field) 
    setattr(target, field, property(func)) 

patch_me(Foo, 'entries', dict) 
+0

Stai aggiungendo un * attributo di classe *, che è condiviso tra tutte le istanze. Se lo aggiungi alle istanze, le istanze * già create * avranno il nuovo attributo? – jonrsharpe

+0

Perché non puoi fare 'a.entries = {'1': 1}' invece? – Vincent

risposta

1

Di solito, gli attributi vengono aggiunti o dalla funzione __init__() o dopo un'istanza:

foo = Foo() 
foo.bar = 'something' # note case 

Se si desidera fai questo automaticamente, l'ereditarietà è di gran lunga il modo più semplice per farlo:

class Baz(Foo): 
    def __init__(self): 
     super().__init__() # super() needs arguments in 2.x 
     self.bar = 'something' 

Si noti che le classi non devono apparire al livello più alto di un modulo Python. È possibile dichiarare una classe all'interno di una funzione:

def make_baz(value): 
    class Baz(Foo): 
     def __init__(self): 
      super().__init__() # super() needs arguments in 2.x 
      self.bar = value() 
    return Baz() 

Questo esempio creerà una nuova classe ogni volta che viene chiamato make_baz(). Potrebbe essere o non essere quello che vuoi. Probabilmente sarebbe più semplice per fare proprio questo:

def make_foo(value): 
    result = Foo() 
    result.bar = value() 
    return result 

se siete veramente impostato su scimmia-patching classe originale, il codice di esempio che hai fornito è più o meno il modo più semplice di farlo. Potresti prendere in considerazione l'uso della sintassi del decoratore per property(), ma si tratta di una modifica minore. Dovrei anche notare che sarà non invocare il nome doppio manomissione, che è probabilmente una buona cosa perché significa che non è possibile entrare in conflitto con nessun nome usato dalla classe stessa.

Problemi correlati