2015-06-03 12 views
8

Vorrei sapere se esiste un modo per "collegare" due attributi di una classe o per assegnare 2 nomi a uno stesso attributo?2 nomi per lo stesso attributo

Ad esempio, attualmente sto lavorando a uno script che crea un triangolo dai dati forniti dagli utenti. Il mio triangolo è ABC. I lati di questo triangolo sono AB, BC e CA. Quindi il triangolo ha questi 3 attributi (self.AB, self.BC, self.CA). Ma AB = BA, quindi vorrei consentire agli utenti di fare print myInstance.BA anziché print myInstance.AB.

Quindi ho pensato di creare l'attributo self.AB e la proprietà BA (che restituisce self.AB). Quel lavoro bene quando cerco di fare print myInstance.BA invece di print myInstance.AB ma io sono avido ...

Vorrei anche per consentire agli utenti di fare myInstance.BA = 5 invece di myInstance.AB = 5 e durante questa operazione anche modificare l'attributo AB.

C'è un modo per farlo?

risposta

11

Le proprietà Python possono avere setter. Quindi tutto ciò che serve è

class Foo(object): 

    @property 
    def BA(self): 
     return self.AB 

    @BA.setter 
    def BA(self, value): 
     self.AB = value 

E insipred da @ di amccormack risposta, se si può contare su l'ordine dei nomi degli attributi, questo funziona più genericamente per esempio bordi bc, cd:

class Foo(object): 


     def __init__(self): 
      self.ab = 100 

     def __getattr__(self, name): 
      return getattr(self, "".join(sorted(name))) 

     def __setattr__(self, name, value): 
      super(Foo, self).__setattr__("".join(sorted(name)), value) 


    f = Foo() 

    print f.ba 
    f.ba = 200 
    print f.ba 
+0

Bug: Aggiungere la seguente riga dopo l'ultima riga per vedere l'errore: 'f.ab stampa, f.ba' –

+0

@HaiVu Questo è perché ci era un errore di battitura nell'esempio. '__setattr__' è stato digitato in modo errato. – amccormack

3

Un modo per farlo è quello di memorizzare i fianchi in un'implementazione personalizzata di un dizionario, come descritto in this SO answer.

Il vantaggio di questa tecnica è che non è necessario sapere quali saranno i nomi dei lati durante la scrittura del codice.

Quello che abbiamo fatto è stato modificare la funzione di ricerca hash in modo che prima che il dizionario cerchi una chiave, ordina la chiave. Poiché la chiave è ordinata, ba diventa ab, ecc. L'ordinamento avviene nella funzione __keytransform__ all'interno della classe SideDict.

import collections 


class TransformedDict(collections.MutableMapping): 
    """A dictionary that applies an arbitrary key-altering 
     function before accessing the keys""" 

    def __init__(self, *args, **kwargs): 
     self.store = dict() 
     self.update(dict(*args, **kwargs)) # use the free update to set keys 

    def __getitem__(self, key): 
     return self.store[self.__keytransform__(key)] 

    def __setitem__(self, key, value): 
     self.store[self.__keytransform__(key)] = value 

    def __delitem__(self, key): 
     del self.store[self.__keytransform__(key)] 

    def __iter__(self): 
     return iter(self.store) 

    def __len__(self): 
     return len(self.store) 

    def __keytransform__(self, key): 
     return key 

class SideDict(TransformedDict): 

    def __keytransform__(self, key): 
     return ''.join(sorted(key)) 

side=SideDict() 
print 'assign 3 to abc' 
side['abc']=3 
print "side['abc']", side['abc'] 
print 'assign 5 to abc' 
side['bac']=5 
print "side['abc']", side['abc'] 
print "side['bca']", side['bca'] 

L'esecuzione di questo codice produce:

assign 3 to abc 
side['abc'] 3 
assign 5 to abc 
side['abc'] 5 
side['bca'] 5 
+0

Questo sembra interessante, ma non dovresti veramente definire il tuo '__magicmethods__'; perché non solo '_key_transform'? – jonrsharpe

+0

Esatto, e vedrai lo stesso commento sulla risposta SO a cui mi sono collegato. L'ho mantenuto lo stesso per coerenza con le risposte, ma sì, dovremmo evitare di creare i nostri stessi nomi di metodi magici. – amccormack

+0

Credo che avrei dovuto leggere prima ...! – jonrsharpe

Problemi correlati