По тому, що ви написали, вам не вистачає критичного розуміння: різниця між класом і об'єктом. __init__не ініціалізує клас, він ініціалізує екземпляр класу або об'єкта. Кожна собака має колір, але собаки як клас не мають. У кожної собаки чотири або менше футів, але клас собак немає. Клас - це поняття предмета. Побачивши Фідо і Пляму, ти впізнаєш їхню схожість, їх собачість. Ось клас.
Коли ти кажеш
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 мільйонів собак. Це властивість класу Собака. Фідо не має нічого спільного з чисельністю 200 мільйонів, а також з Spot. Це називається "атрибут класу", на відміну від "атрибутів екземпляра", які є colourабо legsвище.
Тепер, до чогось менш собачого і більше пов'язаного з програмуванням. Як я пишу нижче, клас додавати речі не є розумним - що це за клас? Заняття в Python складають колекції різних даних, які ведуть себе аналогічно. Клас собак складається з Фідо і Пляма та 199999999998 інших подібних до них тварин, всі вони визирають на ліхтариках. З чого складається клас для додавання речей? За якими властивими їм даними вони відрізняються? І якими діями вони поділяються?
Однак цифри ... це цікавіші предмети. Скажіть, цілі. Їх багато, набагато більше, ніж собак. Я знаю, що в Python вже є цілі числа, але давайте пограємо німо і "реалізуємо" їх знову (шляхом обману та використання цілих чисел Python).
Отже, Integers - це клас. Вони мають деякі дані (значення) та деякі поведінки ("додайте мене до цього іншого числа"). Покажемо це:
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), але ми зараз ігноруємо. У реальному коді ми б не стали; ми перевіримо це, і, можливо, навіть примусимо його ("ти не ціле число?
Ми могли навіть визначити дроби. Дроби також знають, як додати себе.
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буде те , що виявиться новою Собакою; в межах MyIntegers 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__чиновник заповнює його вперше.
Ясніше?
EDIT : Розширення на коментар нижче:
Ви маєте на увазі перелік об’єктів , чи не так?
Перш за все, fidoнасправді це не об’єкт. Це змінна, яка наразі містить об'єкт, як і коли ви говорите x = 5, xце змінна, що містить число п'ять. Якщо згодом ви передумаєте, ви можете fido = Cat(4, "pleasing")(поки ви створили клас Cat) і fidoз цього моменту "містити" об'єкт кішки. Якщо ви це зробите 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__) полягає в тому, щоб описати, як перетворити об'єкт у рядок, як, наприклад, при його друкуванні.