По тому, что вы написали, вам не хватает критического понимания: разницы между классом и объектом. __init__
не инициализирует класс, он инициализирует экземпляр класса или объекта. У каждой собаки есть окрас, но у собак как у класса нет. У каждой собаки четыре или меньше фута, но у класса собак нет. Класс - это понятие объекта. Когда вы видите Fido и Spot, вы узнаете их сходство, их собачье. Это класс.
Когда вы говорите
class Dog:
def __init__(self, legs, colour):
self.legs = legs
self.colour = colour
fido = Dog(4, "brown")
spot = Dog(3, "mostly yellow")
Вы говорите, Фидо - коричневая собака с четырьмя ногами, а Спот - немного калека и в основном желтый. Функция __init__
называется конструктором или инициализатором и автоматически вызывается при создании нового экземпляра класса. В рамках этой функции вновь созданному объекту присваивается параметр self
. Обозначение self.legs
является атрибутом с именем legs
объекта в переменной self
. Атрибуты подобны переменным, но они описывают состояние объекта или конкретные действия (функции), доступные для объекта.
Однако обратите внимание, что вы не устанавливаете colour
для самой собачки - это абстрактное понятие. Есть атрибуты, которые имеют смысл на занятиях. Например, population_size
является одним из таких - не имеет смысла считать Фидо, потому что Фидо всегда один. Имеет смысл считать собак. Допустим, в мире 200 миллионов собак. Это собственность класса Dog. Фидо не имеет ничего общего с числом 200 миллионов, как и Спот. Он называется «атрибут класса», а не «атрибуты экземпляра», которые colour
или legs
выше.
Теперь о чем-то менее собачьем и более связанном с программированием. Как я пишу ниже, класс для добавления вещей не имеет смысла - что это за класс? Классы в Python состоят из наборов различных данных, которые ведут себя одинаково. Класс собак состоит из Fido и Spot и 199999999998 других животных, похожих на них, все они мочатся на фонарных столбах. Из чего состоит класс для добавления вещей? Чем они отличаются? И какие действия они разделяют?
Однако цифры ... это более интересные темы. Скажи, целые числа. Их много, намного больше, чем собак. Я знаю, что в Python уже есть целые числа, но давайте поиграем и «внедрим» их снова (обманывая и используя целые числа Python).
Итак, целые числа - это класс. У них есть некоторые данные (значение) и некоторые виды поведения («добавь меня к этому другому числу»). Покажем это:
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
Это немного хрупко (мы предполагаем, что other
будет MyInteger), но мы сейчас проигнорируем. В реальном коде мы бы не стали; мы проверим это, чтобы убедиться, и, возможно, даже приведем в исполнение («черт возьми, вы не целое число? у вас есть 10 наносекунд, чтобы стать одним! 9 ... 8 ....»)
Мы могли бы даже определить дроби. Фракции также умеют добавлять себя.
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)
Дробей даже больше, чем целых чисел (не совсем, но компьютеры этого не знают). Давайте сделаем два:
half = MyFraction(1, 2)
third = MyFraction(1, 3)
five_sixths = half.add(third)
print five_sixths.numerator
# ==> 5
print five_sixths.denominator
# ==> 6
Вы на самом деле ничего не объявляете здесь. Атрибуты похожи на переменную нового типа. Нормальные переменные имеют только одно значение. Допустим, вы пишете colour = "grey"
. Вы не можете иметь другую переменную с именем colour
, которая является "fuchsia"
- не в том же месте в коде.
Массивы решают это до некоторой степени. Если вы говорите colour = ["grey", "fuchsia"]
, вы поместили два цвета в переменную, но вы различаете их по их положению (в данном случае 0 или 1).
Атрибуты - это переменные, которые связаны с объектом.Как и в случае с массивами, мы можем иметь множество colour
переменных, для разных собак .Итак, fido.colour
- это одна переменная, а spot.colour
- это другая.Первый связан с объектом в переменной fido
;второй spot
.Теперь, когда вы вызываете Dog(4, "brown")
или three.add(five)
, всегда будет невидимый параметр, который будет назначен дополнительному висячему в начале списка параметров.Он обычно называется self
и получит значение объекта перед точкой.Таким образом, в __init__
(конструкторе) Пса self
будет тем, чем окажется новый Пёс;в пределах MyInteger
add
, self
будет привязан к объекту в переменной three
.Таким образом, three.value
будет той же переменной вне add
, что и self.value
в add
.
Если я скажу the_mangy_one = fido
, я начну ссылаться на объект, известный как fido
с еще одним именем.Отныне fido.colour
- это та же переменная, что и the_mangy_one.colour
.
Итак, вещи внутри __init__
.Вы можете думать о них как о пометках в свидетельстве о рождении собаки.colour
само по себе является случайной величиной, может содержать что угодно.fido.colour
или self.colour
похоже на поле формы на паспорте собаки;и __init__
- клерк, заполняющий его в первый раз.
Есть что-нибудь яснее?
РЕДАКТИРОВАТЬ : расширение комментария ниже:
Вы имеете в виду список объектов , не так ли?
Прежде всего, fido
на самом деле не объект.Это переменная, которая в настоящее время содержит объект, точно так же, как когда вы говорите x = 5
, x
- это переменная, в настоящее время содержащая число пятьЕсли позже вы передумаете, вы можете сделать fido = Cat(4, "pleasing")
(если вы создали класс Cat
), и с этого момента fido
будет "содержать" объект cat.Если вы сделаете fido = x
, он будет содержать число пять, а не объект животного вообще.
Класс сам по себе не знает своих экземпляров, если вы специально не напишите код, чтобы отслеживать их.Например:
class Cat:
census = [] #define census array
def __init__(self, legs, colour):
self.colour = colour
self.legs = legs
Cat.census.append(self)
Здесь census
- это атрибут уровня класса Cat
class.
fluffy = Cat(4, "white")
spark = Cat(4, "fiery")
Cat.census
# ==> [<__main__.Cat instance at 0x108982cb0>, <__main__.Cat instance at 0x108982e18>]
# or something like that
Обратите внимание, что вы не получите [fluffy, sparky]
.Это просто имена переменных.Если вы хотите, чтобы сами кошки имели имена, вам нужно создать отдельный атрибут для имени, а затем переопределить метод __str__
, чтобы вернуть это имя.Цель этого метода (то есть функция, связанная с классом, как и add
или __init__
) состоит в том, чтобы описать, как преобразовать объект в строку, например, когда вы ее распечатываете.