Pelo que você escreveu, você está perdendo uma parte crítica do entendimento: a diferença entre uma classe e um objeto. __init__
não inicializa uma classe, inicializa uma instância de uma classe ou um objeto. Cada cão tem cor, mas os cães como classe não. Cada cão tem quatro ou menos pés, mas a classe de cães não. A classe é um conceito de um objeto. Quando você vê o Fido e o Spot, reconhece a semelhança entre eles e sua dogmática. Essa é a aula.
Quando voce diz
class Dog:
def __init__(self, legs, colour):
self.legs = legs
self.colour = colour
fido = Dog(4, "brown")
spot = Dog(3, "mostly yellow")
Você está dizendo, Fido é um cachorro marrom com 4 pernas, enquanto Spot é um pouco aleijado e é principalmente amarelo. A __init__
função é chamada de construtor ou inicializador e é chamada automaticamente quando você cria uma nova instância de uma classe. Dentro dessa função, o objeto recém-criado é atribuído ao parâmetro self
. A notação self.legs
é um atributo chamada legs
do objecto na variável self
. Os atributos são variáveis semelhantes, mas descrevem o estado de um objeto ou ações (funções) específicas disponíveis para o objeto.
No entanto, observe que você não colour
escolhe a doghood - é um conceito abstrato. Existem atributos que fazem sentido nas classes. Por exemplo, population_size
é um desses - não faz sentido contar o Fido porque o Fido é sempre um. Faz sentido contar cães. Digamos que existem 200 milhões de cães no mundo. É propriedade da classe Dog. Fido não tem nada a ver com o número 200 milhões, nem o Spot. É chamado de "atributo de classe", em oposição a "atributos de instância" que são colour
ou legs
acima.
Agora, para algo menos canino e mais relacionado à programação. Enquanto escrevo abaixo, a classe para adicionar coisas não é sensata - do que é uma classe? As classes em Python compõem coleções de dados diferentes, que se comportam de maneira semelhante. A classe de cães consiste em Fido e Spot e 199999999998 outros animais semelhantes a eles, todos mijando em postes de luz. Em que consiste a classe para adicionar coisas? Por quais dados inerentes a eles eles diferem? E que ações eles compartilham?
No entanto, números ... esses são assuntos mais interessantes. Diga, Inteiros. Há muitos deles, muito mais que cães. Eu sei que o Python já tem números inteiros, mas vamos nos fazer de bobo e "implementá-los" novamente (trapaceando e usando os números inteiros do Python).
Então, Inteiros são uma classe. Eles têm alguns dados (valor) e alguns comportamentos ("adicione-me a esse outro número"). Vamos mostrar isso:
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
Isso é um pouco frágil (estamos assumindo other
que será um MyInteger), mas ignoraremos agora. No código real, nós não; nós o testávamos para ter certeza, e talvez até o coagia ("você não é um número inteiro? por golly, você tem 10 nanossegundos para se tornar um! 9 ... 8 ....")
Poderíamos até definir frações. As frações também sabem como se adicionar.
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)
Há ainda mais frações do que números inteiros (na verdade não, mas os computadores não sabem disso). Vamos fazer dois:
half = MyFraction(1, 2)
third = MyFraction(1, 3)
five_sixths = half.add(third)
print five_sixths.numerator
# ==> 5
print five_sixths.denominator
# ==> 6
Você não está realmente declarando nada aqui. Os atributos são como um novo tipo de variável. Variáveis normais possuem apenas um valor. Digamos que você escreva colour = "grey"
. Você não pode ter outra variável com o nome colour
que está "fuchsia"
- não está no mesmo lugar no código.
Matrizes resolvem isso até certo ponto. Se você disser colour = ["grey", "fuchsia"]
, você empilhou duas cores na variável, mas as distingue pela posição (0 ou 1, neste caso).
Atributos são variáveis vinculadas a um objeto. Assim como as matrizes, podemos ter muitas colour
variáveis em cães diferentes . Então, fido.colour
é uma variável, mas spot.colour
é outra. O primeiro está vinculado ao objeto dentro da variável fido
; o segundo spot
. Agora, quando você chama Dog(4, "brown")
, ou three.add(five)
, sempre haverá um parâmetro invisível, que será atribuído ao extra pendente na frente da lista de parâmetros. É chamado convencionalmente self
e obterá o valor do objeto na frente do ponto. Assim, dentro do cão __init__
(construtor), self
será o que o novo cão se tornará; dentro MyInteger
's add
, self
irá ser ligado ao objecto na variável three
. Portanto,three.value
será a mesma variável fora do add
, como self.value
dentro do add
.
Se eu disser the_mangy_one = fido
, começarei a me referir ao objeto conhecido como fido
com outro nome. A partir de agora, fido.colour
é exatamente a mesma variável que the_mangy_one.colour
.
Então, as coisas dentro do __init__
. Você pode pensar nelas como anotando coisas na certidão de nascimento do cão. colour
por si só é uma variável aleatória, pode conter qualquer coisa. fido.colour
ou self.colour
é como um campo de formulário na folha de identidade do cão; e __init__
é o funcionário preenchendo-o pela primeira vez.
Mais claro?
EDIT : Expandindo no comentário abaixo:
Você quer dizer uma lista de objetos , não é?
Primeiro de tudo, fido
na verdade não é um objeto. É uma variável que atualmente contém um objeto, assim como quando você diz x = 5
, x
é uma variável que atualmente contém o número cinco. Se você mudar de idéia mais tarde, poderá fazê-lo fido = Cat(4, "pleasing")
(desde que tenha criado uma classe Cat
) e fido
, a partir de então, "conterá" um objeto gato. Se o fizer fido = x
, ele conterá o número cinco, e não um objeto animal.
Uma classe por si só não conhece suas instâncias, a menos que você escreva um código especificamente para acompanhá-las. Por exemplo:
class Cat:
census = [] #define census array
def __init__(self, legs, colour):
self.colour = colour
self.legs = legs
Cat.census.append(self)
Aqui census
está um atributo de Cat
classe no nível de 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
Note que você não receberá [fluffy, sparky]
. Esses são apenas nomes de variáveis. Se você deseja que os próprios gatos tenham nomes, é necessário criar um atributo separado para o nome e substituir o __str__
método para retornar esse nome. O objetivo deste método (isto é, função vinculada à classe, exatamente como add
ou __init__
) é descrever como converter o objeto em uma string, como quando você o imprime.