По тому, що ви написали, вам не вистачає критичного розуміння: різниця між класом і об'єктом. __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
буде те , що виявиться новою Собакою; в межах MyInteger
s 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__
) полягає в тому, щоб описати, як перетворити об'єкт у рядок, як, наприклад, при його друкуванні.