Почему мы используем __init__ в классах Python?

У меня возникли проблемы с пониманием инициализации классов.

Что с ними связано и как мы знаем, что включать в них? Нужно ли писать в классах разные типы мышления и создания функций (я полагал, что могу просто создавать функции, а затем просто переносить их в класс, чтобы я мог их повторно использовать).

Вот пример:

class crawler:
  # Initialize the crawler with the name of database
  def __init__(self,dbname):
    self.con=sqlite.connect(dbname)

  def __del__(self):
    self.con.close()

  def dbcommit(self):
    self.con.commit()

Или другой пример кода:

class bicluster:
  def __init__(self,vec,left=None,right=None,distance=0.0,id=None):
    self.left=left
    self.right=right
    self.vec=vec
    self.id=id
    self.distance=distance

Есть так много классов с __init__, с которыми я сталкиваюсь при попытке прочитать код других людей, но я не понимаю логику их создания.

Ответ 1

По тому, что вы написали, вам не хватает критического понимания: разница между классом и объектом. __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")

Вы говорите, Фидо - коричневая собака с 4 ногами, в то время как Пятно - немного калека и в основном желтое. Функция __init__ называется конструктором или инициализатором и автоматически вызывается при создании нового экземпляра класса. Внутри этой функции вновь созданный объект присваивается параметру self. Обозначение self.legs - это атрибут legs объекта в переменной self. Атрибуты являются подобными переменными, но они описывают состояние объекта или определенные действия (функции), доступные объекту.

Однако обратите внимание, что вы не устанавливаете colour для самой собаки - это абстрактное понятие. Есть атрибуты, которые имеют смысл в классах. Например, population_size является одним из таких - нет смысла считать Fido, потому что Fido всегда один. Имеет смысл считать собак. Скажем, в мире насчитывается 200 миллионов собак. Это свойство класса Dog. Фидо не имеет никакого отношения к числу 200 миллионов, а также к Spot. Он называется "атрибутом класса", в отличие от "атрибутов экземпляра", которые выше 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 behaviour of adding another integer
# now, eight.value is three.value + five.value = 3 + 5 = 8
print eight.value
# ==> 8

Это немного хрупкий (мы предполагаем, что other будет MyInteger), но мы проигнорируем сейчас. В реальном коде мы бы этого не сделали; мы бы протестировали его, чтобы убедиться, и, возможно, даже принуждаем его ( "вы не целочисленны" по golly, у вас есть 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 и получит значение объекта перед точкой. Таким образом, внутри Dog __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.

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__), состоит в том, чтобы описать, как преобразовать объект в строку, например, когда вы распечатываете ее.

Ответ 2

Чтобы внести свои 5 центов в подробное объяснение из Amadan.

Если классы являются описанием типа "абстрактным". Объектами являются их реализации: живое дыхание. В объектно-ориентированном мире есть основные идеи, которые вы можете почти назвать сущностью всего. Это:

  • инкапсуляция (не будем подробно останавливаться на этом)
  • наследование
  • полиморфизм

У объектов есть одна или несколько характеристик (= Атрибуты) и поведения (= Методы). Поведение в основном зависит от характеристик. Классы определяют, что поведение должно выполнять в общем виде, но пока класс не реализуется (экземпляр) как объект, он остается абстрактным понятием возможности.  Позвольте мне проиллюстрировать с помощью "наследования" и "полиморфизма".

    class Human:
        gender
        nationality
        favourite_drink
        core_characteristic
        favourite_beverage
        name
        age

        def love    
        def drink
        def laugh
        def do_your_special_thing                

    class Americans(Humans)
        def drink(beverage):
            if beverage != favourite_drink: print "You call that a drink?"
            else: print "Great!" 

    class French(Humans)
        def drink(beverage, cheese):
            if beverage == favourite_drink and cheese == None: print "No cheese?" 
            elif beverage != favourite_drink and cheese == None: print "Révolution!"

    class Brazilian(Humans)
        def do_your_special_thing
            win_every_soccer_world_cup()

    class Germans(Humans)
        def drink(beverage):
            if favourite_drink != beverage: print "I need more beer"
            else: print "Lecker!" 

    class HighSchoolStudent(Americans):
        def __init__(self, name, age):
             self.name = name
             self.age = age

jeff = HighSchoolStudent(name, age):
hans = Germans()
ronaldo = Brazilian()
amelie = French()

for friends in [jeff, hans, ronaldo]:
    friends.laugh()
    friends.drink("cola")
    friends.do_your_special_thing()

print amelie.love(jeff)
>>> True
print ronaldo.love(hans)
>>> False

Некоторые характеристики определяют людей. Но каждая национальность несколько отличается. Таким образом, "национальные типы" являются любезными людьми с дополнительными возможностями. "Американцы" - это тип "Людей" и наследуют некоторые абстрактные характеристики и поведение от человеческого типа (базового класса): это наследование. Так что все люди могут смеяться и пить, поэтому все детские классы тоже могут! Наследование (2).

Но поскольку они все одного типа (Type/base-class: Humans), вы можете их иногда обменивать: см. цикл for-loop в конце. Но они будут раскрывать индивидуальную характеристику, и это Полиморфизм (3).

Итак, у каждого человека есть favourite_drink, но каждая национальность склонна к особому напитку. Если вы подклассифицируете национальность от типа людей, вы можете переписать наследуемое поведение, как я показал выше, с помощью метода drink(). Но это все еще на уровне класса и из-за этого все еще является обобщением.

hans = German(favourite_drink = "Cola")

создает экземпляр класса German и я "изменил" значение по умолчанию в начале. (Но если вы вызовете hans.drink( "Молоко" ), он все равно напечатает "Мне нужно больше пива" - явная ошибка... или, может быть, это то, что я назвал бы функцией, если бы я был бы сотрудником более крупной компании.;-)! )

Характеристика типа, например. Немцы (hans) обычно определяются через конструктор (в python: __init__) в момент создания. Это то место, где вы определяете класс, чтобы стать объектом. Вы могли бы назвать жизнь дыхания абстрактной концепцией (классом), заполнив ее индивидуальными характеристиками и став объектом.

Но поскольку каждый объект является экземпляром класса, он разделяет все основные типы признаков и поведение. Это основное преимущество объектно-ориентированной концепции.

Чтобы защитить характеристики каждого объекта, который вы инкапсулируете, вы пытаетесь связать поведение и характеристику и затруднить ее работу вне объекта. Эта инкапсуляция (1)

Ответ 3

Это просто инициализировать переменные экземпляра.

например. создайте экземпляр crawler с определенным именем базы данных (из вашего примера выше).

Ответ 4

Следуя примеру автомобиля: когда вы получаете автомобиль, вы просто не получаете случайную машину, я имею в виду, вы выбираете цвет, марку, количество мест и т.д. И некоторые вещи также "инициализируются" без вашего выбора, например, количества колес или регистрационного номера.

class Car:
    def __init__(self, color, brand, number_of_seats):
        self.color = color
        self.brand = brand
        self.number_of_seats = number_of_seats
        self.number_of_wheels = 4
        self.registration_number = GenerateRegistrationNumber()

Итак, в методе __init__ вы определяете атрибуты создаваемого экземпляра. Итак, если нам нужен синий автомобиль Renault, для 2 человек мы бы инициализировали или использовали экземпляр Car, например:

my_car = Car('blue', 'Renault', 2)

Таким образом мы создаем экземпляр класса Car. __init__ - это тот, который обрабатывает наши конкретные атрибуты (например, color или brand) и генерирует другие атрибуты, такие как registration_number.

Ответ 5

Классы - это объекты с атрибутами (состояние, характеристика) и методы (функции, емкости), которые являются специфическими для этого объекта (например, белый цвет и сила полета, соответственно, для утки).

Когда вы создаете экземпляр класса, вы можете дать ему некоторую начальную личность (состояние или характер, как имя и цвет ее платья для новорожденного). Вы делаете это с помощью __init__.

В основном __init__ автоматически задает характеристики экземпляра, когда вы вызываете instance = MyClass(some_individual_traits).

Ответ 6

Функция __init__ устанавливает все переменные-члены в классе. Итак, как только ваш bicluster будет создан, вы сможете получить доступ к члену и получить значение обратно:

mycluster = bicluster(...actual values go here...)
mycluster.left # returns the value passed in as 'left'

Ознакомьтесь с Python Docs для получения некоторой информации. Вы захотите забрать книгу о концепциях ОО, чтобы продолжить обучение.

Ответ 7

Похоже, вам нужно использовать __init__ в Python, если вы хотите правильно инициализировать изменяемые атрибуты ваших экземпляров.

См. следующий пример:

>>> class EvilTest(object):
...     attr = []
... 
>>> evil_test1 = EvilTest()
>>> evil_test2 = EvilTest()
>>> evil_test1.attr.append('strange')
>>> 
>>> print "This is evil:", evil_test1.attr, evil_test2.attr
This is evil: ['strange'] ['strange']
>>> 
>>> 
>>> class GoodTest(object):
...     def __init__(self):
...         self.attr = []
... 
>>> good_test1 = GoodTest()
>>> good_test2 = GoodTest()
>>> good_test1.attr.append('strange')
>>> 
>>> print "This is good:", good_test1.attr, good_test2.attr
This is good: ['strange'] []

В Java это совсем другое, где каждый атрибут автоматически инициализируется новым значением:

import java.util.ArrayList;
import java.lang.String;

class SimpleTest
{
    public ArrayList<String> attr = new ArrayList<String>();
}

class Main
{
    public static void main(String [] args)
    {
        SimpleTest t1 = new SimpleTest();
        SimpleTest t2 = new SimpleTest();

        t1.attr.add("strange");

        System.out.println(t1.attr + " " + t2.attr);
    }
}

дает результат, который мы интуитивно ожидаем:

[strange] []

Но если вы объявите attr как static, он будет действовать как Python:

[strange] [strange]

Ответ 8

класс Собака (объект):

# Class Object Attribute
species = 'mammal'

def __init__(self,breed,name):
    self.breed = breed
    self.name = name

В приведенном выше примере мы используем виды как глобальные, так как они будут всегда одинаковыми (вид константы, которую вы можете сказать). Когда вы вызываете метод init, тогда вся переменная внутри init (например: порода, имя).

класс Собака (объект):   a = '12'

def __init__(self,breed,name,a):
    self.breed = breed
    self.name = name
   self.a= a

если вы напечатаете приведенный выше пример, вызывая ниже, как это показано

Dog.a 12

Собака ( 'Lab', 'Sam', '10') Dog.a 10

Это означает, что он будет инициализирован только при создании объекта. поэтому все, что вы хотите объявить как постоянное, делает его глобальным и все, что меняется, использует init