Из того, что вы написали, вы упускаете важный элемент понимания: разницу между классом и объектом. __init__
не инициализирует класс, он инициализирует экземпляр класса или объекта. У каждой собаки есть окрас, а у собак как класс - нет. У каждой собаки четыре или меньше лап, но у класса собак нет. Класс - это концепция объекта. Когда вы видите Фидо и Спот, вы узнаете их сходство, их собачью натуру. Это класс.
Когда ты говоришь
class Dog:
def __init__(self, legs, colour):
self.legs = legs
self.colour = colour
fido = Dog(4, "brown")
spot = Dog(3, "mostly yellow")
Вы говорите, что Фидо - коричневая собака с 4 ногами, а Спот немного калека и в основном желтого цвета. __init__
Функция вызывается конструктор, или инициализатор, и автоматически вызывается при создании нового экземпляра класса. В этой функции вновь созданный объект назначается параметру self
. Обозначение self.legs
- это атрибут, вызываемый legs
объектом в переменной self
. Атрибуты похожи на переменные, но они описывают состояние объекта или определенные действия (функции), доступные для объекта.
Однако обратите внимание, что вы не устанавливаете colour
само собачье достоинство - это абстрактное понятие. Есть атрибуты, которые имеют смысл для классов. Например, population_size
одна такая - считать Фидо не имеет смысла, потому что Фидо всегда один. Считать собак имеет смысл. Допустим, в мире 200 миллионов собак. Это собственность класса Dog. Ни Фидо, ни Спот не имеют отношения к числу 200 миллионов. Он называется «атрибутом класса», в отличие от «атрибутов экземпляра», которые есть colour
или legs
выше.
Теперь о чем-то менее собачьем и более связанном с программированием. Как я пишу ниже, класс для добавления вещей не имеет смысла - что это за класс? Классы в Python состоят из наборов разных данных, которые ведут себя одинаково. Класс собак состоит из Фидо и Спота и 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")
, or three.add(five)
, всегда будет невидимый параметр, который будет назначен дополнительному висящему в начале списка параметров. Он называется условно self
и получает значение объекта перед точкой. Таким образом, внутри объекта Dog __init__
(конструктора) self
будет то, чем окажется новый Dog; в 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
класса уровня класса.
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__
) - описать, как преобразовать объект в строку, например, когда вы ее распечатываете.