2009-09-30 31 views
42

Abbastanza semplice, sto imparando Python e non riesco a trovare un riferimento che mi dice come scrivere il seguente:Come definire una classe in Python

public class Team { 
    private String name; 
    private String logo; 
    private int members; 

    public Team(){} 

    // getters/setters 
} 

tardi:

Team team = new Team(); 
team.setName("Oscar"); 
team.setLogo("http://...."); 
team.setMembers(10); 

che è una squadra di classe con le proprietà: nome/logo/membri

Modifica Dopo qualche tentativo ho ottenuto questo:

class Team: 
    pass 

tardi

team = Team() 
team.name="Oscar" 
team.logo="http://..." 
team.members=10 

È questo il modo in python ?? Si sente dispari (proveniente da un linguaggio fortemente tipizzato, naturalmente)

+0

Mi piacerebbe suggerire che qualcuno cambi il titolo in qualcosa che è meglio per la ricerca futura. Qualcosa come "Il miglior modo per definire una classe in Python". – steveha

+0

@steveha: Forse anche se la mia vera domanda era, come scrivo questo in python ... che dire ... – OscarRyz

risposta

43
class Team: 
    def __init__(self): 
    self.name = None 
    self.logo = None 
    self.members = 0 

In Python, in genere non si scrive getter e setter, a meno che non hai davvero un'implementazione non banale per loro (a quel punto si utilizza immobili descrittori).

+0

Martin, qual è la differenza tra la mia ricerca ** classe Team: pass ** e il tuo campione? – OscarRyz

+2

Puoi aggiungere dinamicamente gli attributi come desideri, ma se la classe Team conterrà sempre quegli attributi è più chiaro definirli all'interno della classe e non esternamente. – monkut

+1

È utile per la documentazione in quanto consente alle persone che guardano alla classe di vedere quali attributi sono utili. –

98

Ecco quello che mi sento di raccomandare:

class Team(object): 
    def __init__(self, name=None, logo=None, members=0): 
     self.name = name 
     self.logo = logo 
     self.members = members 

team = Team("Oscar", "http://...", 10) 

team2 = Team() 
team2.name = "Fred" 

team3 = Team(name="Joe", members=10) 

Alcune note su questo.

0) Ho dichiarato che il team eredita da object. Questo rende la squadra una "classe di nuovo stile"; questa è stata una pratica raccomandata in Python da quando è stata introdotta in Python 2.2. (In Python 3.0 e versioni successive, le classi sono sempre "di nuovo stile" anche se si omette la notazione (object), ma l'annotazione non fa danno e rende esplicita l'ereditarietà.) Ecco uno StackOverflow discussion di classi di nuovo stile.

1) Non è necessario, ma ho fatto in modo che l'inizializzatore prenda argomenti facoltativi in ​​modo da poter inizializzare l'istanza su una riga, come ho fatto con team e team3. Questi argomenti sono denominati, quindi è possibile fornire valori come parametri posizionali (come con team) oppure è possibile utilizzare il modulo argument= come ho fatto con team3. Quando si specifica esplicitamente il nome degli argomenti, è possibile specificare argomenti in qualsiasi ordine.

2) Se fosse necessario disporre di funzioni getter e setter, forse per controllare qualcosa, in Python è possibile dichiarare funzioni di metodo speciali. Questo è ciò che intendeva Martin v. Löwis quando diceva "descrittori di proprietà". In Python, è generalmente considerata una buona pratica semplicemente assegnare a variabili membro, e semplicemente fare riferimento a loro per recuperarle, perché è sempre possibile aggiungere i descrittori di proprietà in un secondo momento in caso di necessità. (E se li avete mai bisogno, quindi il codice è meno ingombrante e si ha meno tempo per scrivere Bonus.!)

Ecco un buon collegamento su descrittori di proprietà: http://adam.gomaa.us/blog/2008/aug/11/the-python-property-builtin/

3) E 'davvero non importa se si specificano i valori come parte della chiamata a Team() o se li si inserisce nell'istanza della classe in un secondo momento. L'istanza della classe finale alla quale farai sarà identica.

team = Team("Joe", "http://example.com", 1) 
team2 = Team() 
team2.name = "Joe" 
team2.logo = "http://example.com" 
team2.members = 1 

print team.__dict__ == team2.__dict__ 

Quanto sopra verrà stampato True.(Si può facilmente sovraccaricare l'operatore == per Team casi, e rendere Python fare la cosa giusta quando dici team == team2, ma questo non avviene per impostazione predefinita.)


EDIT: ho lasciato fuori una cosa al di sopra risposta, e mi piacerebbe aggiungerlo ora. Se si esegue la funzione argomento opzionale nella funzione __init__(), è necessario prestare attenzione se si desidera fornire un "mutabile" come argomento facoltativo.

I numeri interi e le stringhe sono "immutabili". Non puoi mai cambiarli sul posto; ciò che accade invece è che Python crea un nuovo oggetto e sostituisce quello che avevi prima.

Elenchi e dizionari sono "mutabili". Puoi mantenere lo stesso oggetto per sempre, aggiungendolo e cancellandolo.

x = 3 # the name "x" is bound to an integer object with value 3 
x += 1 # the name "x" is rebound to a different integer object with value 4 

x = [] # the name "x" is bound to an empty list object 
x.append(1) # the 1 is appended to the same list x already had 

La cosa fondamentale da sapere: gli argomenti facoltativi vengono valutati una sola volta, quando la funzione viene compilata. Pertanto, se si passa un argomento mutabile come argomento facoltativo nello __init__() per la classe, ciascuna istanza della classe condivide un oggetto mutabile. Questo non è quasi mai quello che vuoi.

class K(object): 
    def __init__(self, lst=[]): 
     self.lst = lst 

k0 = K() 
k1 = K() 

k0.lst.append(1) 

print k0.lst # prints "[1]" 
print k1.lst # also prints "[1]" 

k1.lst.append(2) 

print k0.lst # prints "[1, 2]" 

La soluzione è molto semplice:

class K(object): 
    def __init__(self, lst=None): 
     if lst is None: 
      self.lst = [] # bind lst with a new, empty list 
     else: 
      self.lst = lst # bind lst with provided list 

k0 = K() 
k1 = K() 

k0.lst.append(1) 

print k0.lst # prints "[1]" 
print k1.lst # print "[]" 

Questo business di utilizzare un valore di argomento di default di None, poi prova che l'argomento passato is None, si qualifica come un modello di progettazione di Python, o almeno di un idioma dovresti padroneggiare.

+0

E se si desidera che i valori predefiniti delle stringhe siano "" anziché None, è possibile apportare tale modifica alla funzione __init __(). – steveha

+0

+1 Interessante: se si utilizzano i parametri denominati, non otterrò il "metodo __init__ utilizza esattamente 4 parametri utilizzati 0" messaggio di errore ?? ... – OscarRyz

+8

+1: classi di nuovo stile –

Problemi correlati