Da quello che hai scritto, ti manca una parte fondamentale della comprensione: la differenza tra una classe e un oggetto. __init__non inizializza una classe, inizializza un'istanza di una classe o di un oggetto. Ogni cane ha un colore, ma i cani come classe no. Ogni cane ha quattro o meno piedi, ma la classe dei cani no. La classe è un concetto di un oggetto. Quando vedi Fido e Spot, riconosci la loro somiglianza, la loro dogma. Questa è la classe.
Quando dici
class Dog:
def __init__(self, legs, colour):
self.legs = legs
self.colour = colour
fido = Dog(4, "brown")
spot = Dog(3, "mostly yellow")
Stai dicendo, Fido è un cane marrone con 4 zampe mentre Spot è un po 'storpio ed è per lo più giallo. La __init__funzione è chiamata costruttore, o inizializzatore, e viene chiamata automaticamente quando si crea una nuova istanza di una classe. All'interno di quella funzione, l'oggetto appena creato viene assegnato al parametro self. La notazione self.legsè un attributo chiamato legsdell'oggetto nella variabile self. Gli attributi sono un po 'come le variabili, ma descrivono lo stato di un oggetto o particolari azioni (funzioni) disponibili per l'oggetto.
Tuttavia, nota che non sei pronto colourper la dogità stessa: è un concetto astratto. Ci sono attributi che hanno senso nelle classi. Ad esempio, population_sizeè uno di questi - non ha senso contare il Fido perché Fido è sempre uno. Ha senso contare i cani. Diciamo che ci sono 200 milioni di cani nel mondo. È di proprietà della classe Dog. Fido non ha nulla a che fare con il numero 200 milioni, né Spot. Si chiama "attributo di classe", al contrario di "attributi di istanza" che sono colouro legssuperiori.
Ora, a qualcosa di meno canino e più legato alla programmazione. Mentre scrivo di seguito, la classe per aggiungere cose non è sensata: di cosa è una classe? Le classi in Python sono costituite da raccolte di dati diversi, che si comportano in modo simile. La classe di cani è composta da Fido e Spot e 199999999998 altri animali simili a loro, tutti che fanno pipì sui lampioni. In cosa consiste la classe per aggiungere cose? In base a quali dati inerenti a loro differiscono? E quali azioni condividono?
Tuttavia, i numeri ... quelli sono argomenti più interessanti. Dì, numeri interi. Ce ne sono molti, molto di più dei cani. So che Python ha già degli interi, ma facciamo il finto tonto e "implementiamoli" di nuovo (barando e usando gli interi di Python).
Quindi, gli interi sono una classe. Hanno alcuni dati (valore) e alcuni comportamenti ("aggiungimi a questo altro numero"). Mostriamo questo:
class MyInteger:
def __init__(self, newvalue)
# imagine self as an index card.
# under the heading of "value", we will write
# the contents of the variable newvalue.
self.value = newvalue
def add(self, other):
# when an integer wants to add itself to another integer,
# we'll take their values and add them together,
# then make a new integer with the result value.
return MyInteger(self.value + other.value)
three = MyInteger(3)
# three now contains an object of class MyInteger
# three.value is now 3
five = MyInteger(5)
# five now contains an object of class MyInteger
# five.value is now 5
eight = three.add(five)
# here, we invoked the three's behaviour of adding another integer
# now, eight.value is three.value + five.value = 3 + 5 = 8
print eight.value
# ==> 8
Questo è un po 'fragile (supponiamo otherche sarà un MyInteger), ma ora lo ignoreremo. Nel codice reale, non lo faremmo; lo testeremmo per esserne sicuri, e magari lo forzeremmo ("non sei un intero? perbacco, hai 10 nanosecondi per diventarlo! 9 ... 8 ....")
Potremmo anche definire frazioni. Anche le frazioni sanno come sommarsi.
class MyFraction:
def __init__(self, newnumerator, newdenominator)
self.numerator = newnumerator
self.denominator = newdenominator
# because every fraction is described by these two things
def add(self, other):
newdenominator = self.denominator * other.denominator
newnumerator = self.numerator * other.denominator + self.denominator * other.numerator
return MyFraction(newnumerator, newdenominator)
Ci sono anche più frazioni che numeri interi (non proprio, ma i computer non lo sanno). Facciamo due:
half = MyFraction(1, 2)
third = MyFraction(1, 3)
five_sixths = half.add(third)
print five_sixths.numerator
# ==> 5
print five_sixths.denominator
# ==> 6
In realtà non stai dichiarando nulla qui. Gli attributi sono come un nuovo tipo di variabile. Le variabili normali hanno solo un valore. Diciamo che scrivi colour = "grey". Non puoi avere un'altra variabile denominata colourche sia "fuchsia"- non nella stessa posizione nel codice.
Gli array lo risolvono fino a un certo punto. Se dici colour = ["grey", "fuchsia"]di aver impilato due colori nella variabile, ma li distingui in base alla loro posizione (0 o 1, in questo caso).
Gli attributi sono variabili legate a un oggetto. Come con gli array, possiamo avere molte colourvariabili, su cani diversi . Quindi, fido.colourè una variabile, ma spot.colourè un'altra. Il primo è legato all'oggetto all'interno della variabile fido; il secondo spot,. Ora, quando chiami Dog(4, "brown"), o three.add(five), ci sarà sempre un parametro invisibile, che verrà assegnato a quello extra penzolante all'inizio dell'elenco dei parametri. Viene chiamato convenzionalmente selfe otterrà il valore dell'oggetto davanti al punto. Quindi, all'interno del Dog's __init__(costruttore), selfci sarà qualunque cosa risulterà essere il nuovo Dog; all'interno di MyInteger's add, selfsarà associato all'oggetto nella variabile three. Così,three.valuesarà la stessa variabile all'esterno di add, come self.valueall'interno di add.
Se lo dico the_mangy_one = fido, inizierò a fare riferimento all'oggetto noto come fidocon un altro nome. D'ora in poi, fido.colourè esattamente la stessa variabile di the_mangy_one.colour.
Quindi, le cose all'interno del file __init__. Puoi pensare a loro come a annotazioni nel certificato di nascita del cane. colourdi per sé è una variabile casuale, potrebbe contenere qualsiasi cosa. fido.colouro self.colourè come un campo modulo sul foglio di identità del cane; ed __init__è l'impiegato che lo compila per la prima volta.
Qualcosa di più chiaro?
EDIT : Espandendo il commento qui sotto:
Intendi una lista di oggetti , vero?
Prima di tutto, in fidorealtà non è un oggetto. È una variabile, che attualmente contiene un oggetto, proprio come quando dici x = 5, xè una variabile che attualmente contiene il numero cinque. Se in seguito cambi idea, puoi farlo fido = Cat(4, "pleasing")(a patto di aver creato una classe Cat) e fidoda quel momento in poi "conterrai" un oggetto gatto. Se lo fai fido = x, conterrà il numero cinque e non sarà affatto un oggetto animale.
Una classe di per sé non conosce le sue istanze a meno che tu non scriva specificamente codice per tenerne traccia. Per esempio:
class Cat:
census = [] #define census array
def __init__(self, legs, colour):
self.colour = colour
self.legs = legs
Cat.census.append(self)
Ecco censusun attributo di Catclasse a livello di classe.
fluffy = Cat(4, "white")
spark = Cat(4, "fiery")
Cat.census
# ==> [<__main__.Cat instance at 0x108982cb0>, <__main__.Cat instance at 0x108982e18>]
# or something like that
Nota che non otterrai [fluffy, sparky]. Quelli sono solo nomi di variabili. Se vuoi che i gatti stessi abbiano un nome, devi creare un attributo separato per il nome e quindi sovrascrivere il __str__metodo per restituire questo nome. Lo scopo di questo metodo (cioè la funzione associata alla classe, proprio come addo __init__) è descrivere come convertire l'oggetto in una stringa, come quando lo stampi.