Perché devo mappare gli argomenti alle variabili di istanza?

1
Class BankAccount:

    def __init__(self, accID, name, balance):
        self.accID = accID
        self.name = name
        self.balance = balance

Nel codice sopra, perché è necessario mappare tutti i miei argomenti alle variabili di istanza? Sembra solo una perdita di tempo. Sto usando gli stessi nomi identici, e l'unica differenza è che li aggiungo con la parola chiave 'self'. Perché non posso semplicemente usare i nomi degli argomenti? In Python, le cose sembrano diventare piuttosto ingombranti quando il costruttore di un oggetto accetta molti argomenti.

Comprendo l'ovvio - che è un requisito del langugage - ma mi chiedevo perché virtualmente tutti i linguaggi OO sono implementati in questo modo.

    
posta toolshed 17.04.2015 - 18:01
fonte

6 risposte

3

Ci sono casi in cui una semplice mappatura uno-a-uno non è appropriata. L'assegnazione automatica dei parametri alle variabili di istanza funziona solo a volte, non sempre. Forse è necessaria la convalida o può essere lanciata un'eccezione. Forse un parametro deve essere ridimensionato o creato da un altro oggetto.

Considera un BigDecimal Java. Internamente ha un BigInteger e una scala intera. Vedo esattamente un costruttore di molti che accetta quei due tipi di parametri. Perché passare attraverso lo sforzo di avere una mappatura automatica che è di nicchia utilizzare molto del tempo? La maggior parte di questi costruttori probabilmente deve eseguire un'ulteriore elaborazione per convertire i parametri nel suo stato interno. Quelli sono un tipo di costruttore di convenienza.

Inoltre, tale funzione potrebbe incoraggiare astrazioni che perdono . Anche se questa caratteristica da sola non perde, potrebbe incoraggiare i programmatori pigri per fare in modo che tutti i costruttori che scrivono accettino esattamente lo stato interno dell'oggetto come parametri.

    
risposta data 17.04.2015 - 18:12
fonte
3

A causa dell'ereditarietà.

In una lingua senza ereditarietà, il costruttore potrebbe semplicemente mappare i suoi argomenti ai campi dell'oggetto in modo uno a uno. Se il mapping non è uno a uno, è sempre possibile nascondere il costruttore e fornire un metodo statico per eseguire il lavoro e passare i valori finali al costruttore. Caso in questione, questo è il modo in cui molti linguaggi funzionali lo gestiscono.

Tuttavia, con l'ereditarietà, si incontra un problema: è necessario inizializzare i campi della classe genitore. Il linguaggio potrebbe obbligarti a dichiarare il costruttore della sottoclasse in modo tale che includa tutti i campi della classe genitrice, ma quali valori passi? La logica per inizializzarli è bloccata nel metodo della factory static della classe genitore. Dovresti reimplementare quella logica, e questo potrebbe essere impossibile se non hai il codice sorgente e la logica non è documentata.

Detto questo, non c'è motivo per cui il linguaggio non possa fornire zucchero sintattico per questo.

    
risposta data 17.04.2015 - 18:38
fonte
1

Lo scopo di un metodo di costruzione è di costruire un oggetto. I parametri del costruttore sono legati al metodo del costruttore, quindi a meno che non li salvi in variabili d'istanza, questi vengono persi una volta che il metodo del costruttore si spegne di scopo. Questo è il modo in cui i parametri funzionano in qualsiasi metodo; sono locali per il metodo, non globali per la classe.

Il tuo metodo di costruzione potrebbe semplicemente mappare i valori dei parametri alle variabili membro, ma potrebbe fare qualcosa di completamente diverso. Il tuo paradigma di programmazione richiede la flessibilità per permetterti di fare entrambe le cose.

I metodi di costruzione tipicamente non restituiscono nulla. Un metodo ordinario può eseguire un lavoro utile con i parametri senza coinvolgere variabili di istanza, dal momento che puoi effettivamente restituire qualcosa dal metodo.

    
risposta data 17.04.2015 - 18:04
fonte
1

Di solito non hai bisogno di. Scala, per example , mantiene solo gli argomenti del costruttore principale in ambito la vita dell'oggetto. Si scopre che la maggior parte delle volte è tutto ciò di cui hai bisogno, specialmente se supporti i valori predefiniti.

Tuttavia, devi ancora supportare quegli altri casi che enumerano le altre risposte. La maggior parte delle lingue ha ottimizzato il loro design per coprire il maggior numero di casi in modo coerente, piuttosto che ottimizzare per brevità nel caso più frequente a spese di maggiore complessità e minore coerenza nella gestione dei casi meno frequenti.

In parte, questo è dovuto al fatto che come progettista di un linguaggio, è difficile dire quale sarà in realtà il caso più frequente in natura, o quali sarebbero le conseguenze nel mondo reale di un riferimento a un argomento del costruttore che non serve più.

    
risposta data 17.04.2015 - 19:25
fonte
0

I understand the obvious -- that it is a requirement of the language -- but I was wondering why virtually all OO languages are implemented this way.

Perché c'è una differenza tra il tipo (o il costruttore del tipo) e il costruttore (o costruttore di dati). Mescolando questi concetti, stai facendo delle supposizioni su ciò che il programmatore vuole - impedendo loro di avere più costruttori per lo stesso tipo.

Detto questo, C # 6 sta introducendo costruttori primari per fare questo genere di cose:

link

L'ho fatto anche in un'iterazione di Tangent perché volevo esplicitamente unificare i costruttori di tipi e i costruttori di dati, perché legando un singolo costruttore di dati a un tipo reso molto più semplice (leggi: possibile) mescolare i tipi insieme e ancora ottieni un tipo costruibile.

    
risposta data 17.04.2015 - 18:17
fonte
0

Dal punto di vista della struttura del linguaggio: a causa dell'ambito. I parametri passati a una funzione sono validi e accessibili solo all'interno di quella funzione. Le variabili di istanza sono valide e accessibili in ogni funzione.

Inoltre, per definizione i parametri di funzione vengono passati alla funzione da un chiamante. Quindi non risiedono nell'oggetto: risiedono nel chiamante. Devono necessariamente rappresentare due diverse aree fisiche nella memoria.

Suppongo che in linea di principio si possa avere una lingua in cui qualsiasi parametro in una funzione che ha lo stesso nome delle variabili oggetto viene copiato automaticamente prima che venga eseguita la prima riga della funzione. Il mio primo pensiero è che ciò potrebbe causare problemi, perché ci sono sicuramente momenti in cui non vorrai una copia così automatica. Potrebbero esserci test di validità che dovrebbero essere fatti prima di salvare qualsiasi dato. Potremmo voler verificare se un nuovo valore equivale al vecchio valore e quindi ad alcune registrazioni. Etc. Suppongo che qualcuno potrebbe rispondere che in tal caso si potrebbe semplicemente dare al parametro un nome diverso.

Per due o tre variabili, in genere lo vedo come un grosso problema. Sì, quando ci sono 15 variabili passate e tutte devono essere assegnate alla variabile oggetto corretta, è un dolore. Sarei interessato a vedere una lingua che aveva una funzione per farlo in modo pulito.

Francamente, quello che faccio di solito è creare l'oggetto e poi avere una serie di dichiarazioni di assegnazione. Come

myfoo=new Foo();
myfoo.bar=42;
myfoo.plugh="fwacbar";
... etc ...

Questo può essere più chiaro di avere una lunga stringa di valori nel costruttore, dove potrebbe non essere ovvio a quale variabile ogni valore va. (Soprattutto piccoli numeri interi e booleani.) È solo un po 'più di battitura a scrivere le istruzioni di assegnazione piuttosto che una lunga lista di parametri. Nel caso non raro in cui il costruttore viene chiamato una o due volte, potrebbe essere meno digitante, in quanto elimina l'elenco dei parametri e sposta semplicemente i compiti dal costruttore al chiamante.

Ovviamente ha lo svantaggio che funziona solo se tutti i valori sono assegnamenti semplici senza alcuna validazione o manipolazione. E in alcuni casi possiamo dire che un costruttore con tutti i valori produce un oggetto valido e utilizzabile; mentre questa tecnica significa che quasi certamente non lo fa, che alcuni considerano una violazione del contratto di costruzione.

    
risposta data 17.04.2015 - 19:17
fonte

Leggi altre domande sui tag