Пять важных понятий, необходимых для быстрого старта в python ооп
Содержание:
- Подклассы
- Наследование
- Классы Python 3: работа с более чем одним объектом
- Inheritance
- Классы в Python
- Создание собственных метаклассов
- Переменные класса или переменные экземпляра?
- Creating an Object in Python
- Логистическая регрессия
- Обработка после инициализации
- The __init__() Method
- Создание Вложенных Классов В Python
- Документирование классов
- 9.7. Odds and Ends¶
- Для чего нужны методы класса в Python?
- Copying init=False fields after new object creation in replace()
- Create Multiple Functions
- Для чего нужны статические методы класса в Python?
- Переопределение метода
- Создание объекта
- Создание объектов
- Интерфейс
Подклассы
Настоящая сила классов становится очевидной, когда вопрос касается подклассов. Вы, возможно, еще не поняли это, но мы уже создали подкласс, когда создавали класс, основанный на объекте. Другими словами, «подклассифицировали» объект. Так как объект – это не очень интересная тема, предыдущие примеры не уделили должного внимания такому сильному инструменту как подкласс. Давайте подклассифицируем наш класс Vehicle и узнаем, как все это работает.
Python
class Car(Vehicle):
«»»
The Car class
«»»
#———————————————————————-
def brake(self):
«»»
Override brake method
«»»
return «The car class is breaking slowly!»
if __name__ == «__main__»:
car = Car(«yellow», 2, 4, «car»)
car.brake()
‘The car class is breaking slowly!’
car.drive()
«I’m driving a yellow car!»
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
classCar(Vehicle) «»» The Car class #———————————————————————- defbrake(self) «»» Override brake method return»The car class is breaking slowly!» if__name__==»__main__» car=Car(«yellow»,2,4,»car») car.brake() ‘The car class is breaking slowly!’ car.drive() «I’m driving a yellow car!» |
В этом примере, мы подклассифицировали класс Vehicle. Вы могли заметить, что мы не использовали методы __init__ и drive. Причина в том, что когда мы хотим сделать из класса подкласс, мы уже имеем все атрибуты и методы, только если мы не переопределяем их. Таким образом, вы могли заметить, что мы переопределяем метод brake и указываем ему делать кое-что другое. Другие методы остаются такими же, какими они и были до этого. Так что, когда вы указываете автомобилю тормозить, он использует оригинальный метод, и мы узнали, что мы водим желтый автомобиль. Когда мы используем значения родительского класса по умолчанию – мы называем это наследование.
Это достаточно большой раздел в объектно-ориентированном программировании. Это также простой пример полиморфизма. Полиморфические классы имеют одинаковый интерфейс (методы, атрибуты), но они не контактируют друг с другом. Касаемо полиморфизма в Пайтоне, не очень сложно выяснить, что интерфейсы являются идентичными. С этого момента мы знакомимся с понятием утиная типизация. Суть утиной типизации заключается в том, что если это ходит как утка, и крякает как утка – значит, это должна быть утка.
В Пайтоне, если класс содержит методы, которые называются одинаково, то не имеет значения, если реализация этих методов отлична. В любом случае, вам пока не нужно знать все подробности использования классов в Пайтоне. Вам нужно только хорошо разбираться в терминологии, если вы захотите углубиться в вопрос глубже. Вы можете найти много хороших примеров полиморфизма в Python, которые помогут вам понять, как и зачем вы можете использовать этот концепт в собственных приложениях.
Наследование
Когда вы используете декоратор , он проходит по всем родительским классам начиная с object и для каждого найденного класса данных сохраняет поля в упорядоченный словарь (ordered mapping), затем добавляя свойства обрабатываемого класса. Все сгенерированные методы используют поля из полученного упорядоченного словаря.
Как следствие, если родительский класс определяет значения по умолчанию, вы должны будете поля определять со значениями по умолчанию.
Так как упорядоченный словарь хранит значения в порядке вставки, то для следующих классов
будет сгенерирован метод с такой сигнатурой:
Классы Python 3: работа с более чем одним объектом
Классы позволяют создавать много похожих объектов на основе одного образца. Чтобы понять, как это работает, добавим еще один объект Shark в нашу программу:
shark.py
classShark: def__init__(self, name): self.name = name defswim(self): print(self.name + " is swimming.") defbe_awesome(self): print(self.name + " is being awesome.") defmain(): sammy = Shark("Sammy") sammy.be_awesome() stevie = Shark("Stevie") stevie.swim() if __name__ == "__main__": main()
Мы создали второй объект Shark с именем stevie, и передали ему имя «Stevie». В этом примере используются методы be_awesome() с sammy и метод swim() со stevie.
Запустим программу:
python shark.py Вывод Sammy is being awesome. Stevie is swimming.
Результат показывает, что мы используем два разных объекта: объект sammy и объект stevie. Они оба относятся к классу Shark.
Классы позволяют создавать более одного объекта по одному и тому же шаблону, не создавая каждый из них с нуля.
Inheritance
Inheritance is a key concept in object oriented programming. Classes can inherit from other classes. This basically means that you can create a class based on another class.
So we could create a class and base it on the class. We can then add attributes to that only customers will need, such as how much they’ve spent:
# Create the ‘Person’ class
class Person:
def __init__(self, id, firstname, lastname):
self.id = id
self.firstname = firstname
self.lastname = lastname
# Create the ‘Customer’ class (inherited from the ‘Person’ class)
class Customer(Person):
def __init__(self, id, firstname, lastname, totalspend):
Person.__init__(self, id, firstname, lastname)
self.totalspend = totalspend
def getDetails(self):
return «%s %s (customer %i) has spent %s in total.» % (self.firstname, self.lastname, self.id, self.totalspend)
# Instantiate the ‘Customer’ class
customer = Customer(
12,
«Peter»,
«Griffin»,
13000
)
# Print details
print(customer.getDetails())Result
Peter Griffin (customer 12) has spent 13000 in total.
Here we use a (slightly) stripped down version of our class (from the previous example), then we create a class based on it. We know it’s inherited from the class because we’ve put inside the parentheses (like this .
The class has a function called that returns a string of text about how much the customer has spent. This function uses the string formatting tokens and to insert the customer’s details into the right place. The details are provided after the symbol after the end of the string.
Классы в Python
Классы похожи на образец или прототип для создания объектов. Они определяются с помощью ключевого слова class.
Давайте определим класс Shark, который имеет две связанные с ним функции:
shark.py
classShark: defswim(self): print("The shark is swimming.") defbe_awesome(self): print("The shark is being awesome.")
Поскольку эти функции объявлены под классом Shark, они называются методами. Методы — это особый вид функции, который определен внутри класса.
Аргументом этих функций является слово self, которое является ссылкой на объекты, созданные на основе этого класса. Чтобы ссылаться на экземпляры (или объекты) класса, self всегда будет первым параметром.
Определение этого класса создает шаблон для объекта Shark, который мы сможем определить позже. То есть, если вы запустите программу, приведенную выше, ничего не будет возвращено.
Создание собственных метаклассов
Чтобы создать наш собственный метакласс, нам нужно унаследовать существующий метакласс `type` и переопределить некоторые специальные методы:
__new __() -> Это вызывается перед __init__() . Он отвечает за создание объекта и возвращает его.
__init __() -> Это для инициализации вновь созданного объекта, который передается как параметр (параметр self )
В следующем фрагменте показано, как можно создать метакласс:
class MyMetaclass(type): def __new__(cls, name, bases, dict): print('Creating a new object of', name) # Invoke __new__() method of the metaclass type return super(MyMetaclass, cls).__new__(cls, name, bases, dict) def __init__(cls, name, bases, dict): print('Initialising class', name) super(MyMetaclass, cls).__init__(name, bases, dict)
Теперь, когда мы создали наш собственный метакласс, нам нужно убедиться, что мы создаем другие классы, которые используют наш метакласс.
Для этого мы передаем параметр в определение нового класса, который сообщает классу использовать наш собственный метакласс в качестве собственного метакласса, а не .
class Student(metaclass=MyMetaclass): def __init__(self, name): self.name = name def get_name(self): return self.name
Здесь использует как свой метакласс. Следовательно, при создании экземпляра Student будут вызываться наши собственные методы метакласса вместо метакласса .
stud = Student('Amit') print(stud.get_name()) print('Type of Student object:', type(stud)) print('Type of Student Class:', type(Student))
Вывод
Creating a new object of Student Initialising class Student Amit Type of Student object: <class '__main__.Student'> Type of Student Class: <class '__main__.MyMetaclass'>
В старых версиях Python 2.7 или ниже используется ключевое слово для указания используемого метакласса. Python3 изменил это поведение, чтобы передать в качестве параметра.
Переменные класса или переменные экземпляра?
Когда переменная определяется на уровне класса, она называется переменной класса. Когда переменная определяется в конструкторе, она называется переменной экземпляра.
Переменные класса являются общими для всех экземпляров класса, тогда как переменные экземпляра уникальны для экземпляра
Итак, очень важно понимать, когда использовать переменную класса, а когда — переменную экземпляра
В предыдущих примерах атрибут employee_id уникален для экземпляра Employee, поэтому лучше иметь его в качестве переменной экземпляра и определять в конструкторе.
Предположим, мы хотим отслеживать количество созданных экземпляров сотрудников и выделенных идентификаторов сотрудников. В этом случае мы можем использовать переменные класса для хранения этих данных и обновления экземплярами.
class Employee: count = 0 ids_list = [] def __init__(self, i): self.id = i Employee.count += 1 self.ids_list.append(i) for x in range(0, 10): emp = Employee(x) print(f'Number of employees created = {Employee.count}') print(f'List of employee ids allocated = {Employee.ids_list}') emp = Employee(1000) print(f'List of employee ids allocated = {emp.ids_list}')
Выход:
Number of employees created = 10 List of employee ids allocated = List of employee ids allocated =
Примечание: мы можем получить доступ к переменным класса через имя класса, а также через переменную экземпляра.
Creating an Object in Python
We saw that the class object could be used to access different attributes.
It can also be used to create new object instances (instantiation) of that class. The procedure to create an object is similar to a function call.
This will create a new object instance named harry. We can access the attributes of objects using the object name prefix.
Attributes may be data or method. Methods of an object are corresponding functions of that class.
This means to say, since is a function object (attribute of class), will be a method object.
Output
<function Person.greet at 0x7fd288e4e160> <bound method Person.greet of <__main__.Person object at 0x7fd288e9fa30>> Hello
You may have noticed the parameter in function definition inside the class but we called the method simply as without any arguments. It still worked.
This is because, whenever an object calls its method, the object itself is passed as the first argument. So, translates into .
In general, calling a method with a list of n arguments is equivalent to calling the corresponding function with an argument list that is created by inserting the method’s object before the first argument.
For these reasons, the first argument of the function in class must be the object itself. This is conventionally called self. It can be named otherwise but we highly recommend to follow the convention.
Now you must be familiar with class object, instance object, function object, method object and their differences.
Логистическая регрессия
Сначала мы будем использовать логистическую регрессию. На следующих этапах мы будем использовать область под кривой ROC и матрицу путаницы в качестве метрик ошибок.
Давайте сначала импортируем все, что нам нужно:
Затем мы делаем примерЛогистическая регрессияОбъект и пример модели для учебного набора:
Затем мы предсказываем вероятность того, что гриб ядовит. Помните, мы относимся к грибам как к ядовитым или неядовитым.
Также вам нужно напомнить, что логистическая регрессия возвращает вероятность. А пока давайте установим порог на 0,5. Таким образом, если вероятность больше 0,5, гриб будет классифицирован как ядовитый. Конечно, если вероятность меньше порога, гриб классифицируется как съедобный.
Это именно то, что происходит в ячейке кода ниже:
Обратите внимание, что мы рассчитали вероятности на тестовом наборе. Теперь давайте посмотримМатрица путаницы.Это покажет нам истинно положительные, истинно отрицательные, ложноположительные и ложно отрицательные показатели
Теперь давайте посмотримМатрица путаницы.Это покажет нам истинно положительные, истинно отрицательные, ложноположительные и ложно отрицательные показатели.
Пример путаницы
Мы выводим нашу матрицу путаницы следующим образом:
И вы должны получить:
Удивительно! Наш классификатор идеален! Из приведенной выше матрицы путаницы вы видите, что наши ложноположительные и ложноотрицательные показатели равны 0, что означает, что все грибы были правильно классифицированы как ядовитые или съедобные!
Давайте напечатаем область под кривой ROC. Как известно, для идеального классификатора он должен быть равен 1.
Действительно, кодовый блок выше выводит 1! Мы можем сделать нашу собственную функцию для визуализации кривой ROC:
И вы должны увидеть:
Кривая ROC
Поздравляем! Вы создали идеальный классификатор с базовой моделью логистической регрессии.
Тем не менее, чтобы получить больше опыта, давайте создадим классификатор, используя LDA и QDA, и посмотрим, получим ли мы аналогичные результаты.
Обработка после инициализации
Автосгенерированный метод вызывает метод , если он определен в классе. Как правило он вызывается в форме , однако если в классе определены переменные типа , они будут переданы в качестве параметров метода.
Если метод не был сгенерирован, то он не будет вызываться.
Например, добавим сгенерированное описание книги
Параметры только для инициализации
Одна из возможностей, связанных с методом — параметры, используемые только для инициализации. Если при объявления поля указать в качестве его типа , его значение будет передано как параметр метода . Никак по-другому такие поля не используются в классе данных.
The __init__() Method
Python has a special method called that you can add to your class. The method is invoked whenever an object is created from the class. Therefore you can make use of the method without having to explictly call it.
Here’s a simple example to demonstrate:
# Create the class
class MyClass:
def __init__(self):
self.a = «Hey»
def b(self):
return «Hello World»
# Create an object from the class
o = MyClass()
# Now we can work with the object
print(o.a)
print(o.b())Result
Hey Hello World
We can access the variable using (i.e. ). So if we had an object called and another called then we could use and respectively.
Создание Вложенных Классов В Python
В этом разделе мы в первую очередь сосредоточимся на создании вложенных классов. Для этого давайте рассмотрим пример.
class language: def __init__(self): .specification() def show(self): print("Language:", self.language) class specification: def __init__(self): def display(self): print("type:", self.type) print("Founded:", self.founded) () out.show() .lg ppool.display()
Language: PYTHON type: HIGH-LEVEL Founded: 1991
Здесь выше мы успешно создали вложенный класс . Теперь давайте пройдемся строчка за строчкой и поймем, что мы это сделали. Итак, сначала мы создали класс с именем language. Внутри него мы использовали ключевое слово self. Ключевое слово self-это ключ, через который мы можем получить доступ к атрибутам и методам aнашего созданного класса. Внутри класса language мы создали еще один вложенный класс под названием specification. Там мы точно так же определили спецификации. Наконец, мы получаем желаемый результат.
Документирование классов
Весь код нужно комментировать и документировать. Классы – не исключение. Стоит помнить, что код вы пишите не для себя, и вполне вероятно, что написанное вами придётся поддерживать другим людям. Комментарии повышают читаемость и увеличивают легкость восприятие кода в разы, тем самым экономя время и деньги.
Поэтому вот наша статья о Python-документации.
ООП ещё долгое время будет оставаться передовой парадигмой программирования. Но учить её полезно и по другой причине. Прямая связь объектно-ориентированного программирования с реальным миром помогает глубже понимать устройство и принципы работы, как самого языка, так и написания кода в целом.
9.7. Odds and Ends¶
Sometimes it is useful to have a data type similar to the Pascal “record” or C
“struct”, bundling together a few named data items. An empty class definition
will do nicely:
class Employee pass john = Employee() # Create an empty employee record # Fill the fields of the record john.name = 'John Doe' john.dept = 'computer lab' john.salary = 1000
A piece of Python code that expects a particular abstract data type can often be
passed a class that emulates the methods of that data type instead. For
instance, if you have a function that formats some data from a file object, you
can define a class with methods and that get the
data from a string buffer instead, and pass it as an argument.
Для чего нужны методы класса в Python?
Следующие примеры кода должны сделать понимание метода класса более ясным. Далее рассмотрим пример класса, имеющего дело с информацией о дате (это будет шаблон):
class Date def __init__(self, day=, month=, year=): self.day = day self.month = month self.year = year def string_to_db(self): return f'{self.year}-{self.month}-{self.day}'
Этот класс, очевидно, можно использовать для хранения информации об определенных датах, без информации о часовом поясе (предположим, что все даты представлены в формате UTC).
Здесь есть конструктор , типичный инициализатор экземпляров классов Python, который получает аргументы как типичный метод экземпляра, имея первый необязательный аргумент , который содержит ссылку на вновь созданный экземпляр.
Например есть несколько задач, которые можно решить при помощи будущих методов этого класса, не только определенного для примера метода, банального перевода числовых значений в формат строки с датой для баз данных.
Предположим, что мы хотим создать много экземпляров класса с информацией о дате, поступающей из внешнего источника, в виде строки с форматом . Предположим, нужно сделать это в разных местах исходного кода проекта.
Итак, что для этого необходимо сделать:
- Выполнить синтаксический анализ строки, получить день, месяц и год как три целочисленные переменные или кортеж из трех элементов, включающий эти переменные.
- Создать экземпляр , передав эти значения в конструктор класса при его создании.
Это будет выглядеть так:
>>> string_date = '10.10.2020' >>> day, month, year = map(int, string_date.split('.')) >>> date = Date(day, month, year) >>> date.string_to_db() # '2020-10-10'
Для выполнения этой задачи, например C++ или Java может реализовать такую возможность с перегрузкой метода , но в Python перегрузка отсутствует. Вместо нее необходимо использовать метод класса (декоратор @classmethod).
Создадим еще один «конструктор».
class Date(object): def __init__(self, day=, month=, year=): self.day = day self.month = month self.year = year @classmethod def from_string(cls, date_as_string): day, month, year = map(int, date_as_string.split('.')) date1 = cls(day, month, year) return date1 def string_to_db(self): return f'{self.year}-{self.month}-{self.day}'
Обратите внимание, как используется аргумент в методе класса вместо прямого вызова конструктора класса. Теперь создать новый экземпляр , так же, можно следующим образом:
Теперь создать новый экземпляр , так же, можно следующим образом:
>>> date1 = Date.from_string('30.12.2020') >>> date1.string_to_db() # '2020-12-30' >>> date2 = Date.from_string('01.01.2021') >>> date2.string_to_db() # '2021-1-1'
Рассмотрим приведенную выше реализацию чтобы понять, какие преимущества здесь есть:
- Реализован синтаксический анализ строки даты в одном месте, и теперь его можно использовать повторно.
- Инкапсуляция здесь отлично работает. Если вы думаете, что можете реализовать синтаксический анализ строк как единственную функцию в другом месте, это решение намного лучше соответствует парадигме ООП.
- — это объект, который содержит сам класс, а не его экземпляр. Это довольно круто, потому что, если мы наследуем класс , для всех дочерних элементов также будет определен метод класса .
Используя методы класса, можно добавить столько альтернативных конструкторов, сколько необходимо. Такое поведение может сделать интерфейс создаваемых классов самодокументированным (до определенной степени конечно) и упростить их использование.
Copying init=False fields after new object creation in replace()
Fields that are init=False are by definition not passed to
__init__, but instead are initialized with a default value, or by
calling a default factory function in __init__, or by code in
__post_init__.
A previous version of this PEP specified that init=False fields
would be copied from the source object to the newly created object
after __init__ returned, but that was deemed to be inconsistent
with using __init__ and __post_init__ to initialize the new
object. For example, consider this case:
@dataclass class Square: length: float area: float = field(init=False, default=0.0) def __post_init__(self): self.area = self.length * self.length s1 = Square(1.0) s2 = replace(s1, length=2.0)
Create Multiple Functions
You’d normally put more than one function in a class. You can also pass arguments to the functions as you would any other function.
Here’s an example of a class that groups arithmetic related functions:
# Create the class
class Arithmetic:
def Add(self, x, y):
return x + y
def Subtract(self, x, y):
return x — y
def Multiply(self, x, y):
return x * y
def Divide(self, x, y):
return x / y
# Object 1
a = Arithmetic()
print(a.Add(2, 3))
print(a.Subtract(8, 300))
print(a.Multiply(2, 3))
print(a.Divide(30, 5))
# Object 2
b = Arithmetic()
print(b.Add(22, 33))
print(b.Subtract(88, 3333))
print(b.Multiply(77, 99))
print(b.Divide(555, 444))Result
5 -292 6 6.0 55 -3245 7623 1.25
Для чего нужны статические методы класса в Python?
Рассмотрим пример класса , имеющего дело с информацией о дате из материала о методах класса.
class Date(object): def __init__(self, day=, month=, year=): self.day = day self.month = month self.year = year @classmethod def from_string(cls, date_as_string): day, month, year = map(int, date_as_string.split('.')) date1 = cls(day, month, year) return date1 def string_to_db(self): return f'{self.year}-{self.month}-{self.day}' # создадим экземпляр класса из строки с датой # за это отвечает метод класса `from_string()` >>> date = Date.from_string('30.12.2020') >>> date.string_to_db() # '2020-12-30'
А что если строка будет не того формата, который ждет метод класса ? Посыпятся ошибки? Программа сломается? Что делать? Обернуть создание экземпляра в и ловить ошибку или проще проверить строку с датой на валидность формата?
И так, есть строка даты, которую необходимо каким-то образом проверять и эта задача логически связана с классом . Вот где статический метод может быть полезен.
Добавим статический метод проверки валидности строки с датой в класс :
class Date(object): def __init__(self, day=, month=, year=): self.day = day self.month = month self.year = year @classmethod def from_string(cls, date_as_string): day, month, year = map(int, date_as_string.split('.')) date1 = cls(day, month, year) return date1 @staticmethod def is_date_valid(date_as_string): # не полный пример проверки валидности # и приведен чисто в учебных целях if date_as_string.count('.') == 2 day, month, year = map(int, date_as_string.split('.')) return day <= 31 and month <= 12 and year <= 3999 def string_to_db(self): return f'{self.year}-{self.month}-{self.day}'
Как видно из кода статического метода , у него нет никакого доступа к тому, что такое класс — это в основном просто функция, синтаксически называемая как метод, но без доступа к объекту и его внутренним элементам (атрибутам и другим методам).
Использование класса , в частности, его статического метода:
# список строк с датами dates = '30.12.2020', '30-12-2020', '01.01.2021', '12.31.2020' for string_date in dates # проверяем валидность строки с датой if Date.is_date_valid(string_date): # если все нормально, то создаем #экземпляр из этой строки date = Date.from_string(string_date) # далее делаем, что-то с экземпляром string_to_db = date.string_to_db() print(string_to_db) else print(f'Неправильная дата или формат строки с датой') # 2020-12-30 # Неправильная дата или формат строки с датой # 2020-1-1 # Неправильная дата или формат строки с датой
Переопределение метода
Обратите внимание, что в приведенном выше примере метод __init __() был определен в обоих классах, Triangle и Polygon. Когда это происходит, метод производного класса переопределяет метод базового класса
Это означает, что __init __() в Triangle получает предпочтение перед __init__ в Polygon.
Обычно при переопределении базового метода мы стремимся расширить определение, а не просто заменить его. То же самое делается путем вызова метода в базовом классе из метода в производном классе (вызов Polygon .__ init __() из __init __() в Triangle).
Лучшим вариантом было бы использовать встроенную функцию super(). Итак, super() .__ init __ (3) эквивалентен Polygon .__ init __ (self, 3) и является предпочтительным. Чтобы узнать больше о функции super() в Python, посетите функцию Python super().
Две встроенные функции isinstance() и issubclass() используются для проверки наследования.
Функция isinstance() возвращает True, если объект является экземпляром класса или других классов, производных от него. Каждый класс в Python наследуется от объекта базового класса.
>>> isinstance(t,Triangle) True >>> isinstance(t,Polygon) True >>> isinstance(t,int) False >>> isinstance(t,object) True
Точно так же issubclass() используется для проверки наследования классов.
>>> issubclass(Polygon,Triangle) False >>> issubclass(Triangle,Polygon) True >>> issubclass(bool,int) True
Было полезно224
Нет28
8781cookie-checkНаследование в Python
Создание объекта
Мы увидели, что объект класса можно использовать для доступа к различным атрибутам.
Его также можно использовать для создания новых экземпляров объекта (создания экземпляров) этого класса. Процедура создания объекта аналогична вызову функции.
>>> harry = Person()
Это создаст новый экземпляр объекта с именем harry. Мы можем получить доступ к атрибутам объектов, используя префикс имени объекта.
Атрибуты могут быть данными или методом. Методы объекта ‒ это соответствующие функции этого класса.
Это означает, что поскольку Person.greet является объектом функции (атрибутом класса), Person.greet будет объектом метода.
class Person: "This is a person class" age = 10 def greet(self): print('Hello') # create a new object of Person class harry = Person() # Output: <function Person.greet> print(Person.greet) # Output: <bound method Person.greet of <__main__.Person object>> print(harry.greet) # Calling object's greet() method # Output: Hello harry.greet()
Выход
<function Person.greet at 0x7fd288e4e160> <bound method Person.greet of <__main__.Person object at 0x7fd288e9fa30>> Hello
Вы могли заметить параметр self в определении функции внутри класса, но мы вызвали этот метод просто как harry.greet() без каких-либо аргументов. Это все еще работало.
Это потому, что всякий раз, когда объект вызывает свой метод, сам объект передается в качестве первого аргумента. Итак, harry.greet() переводится как Person.greet (harry).
В общем случае вызов метода со списком из n аргументов эквивалентен вызову соответствующей функции со списком аргументов, который создается путем вставки объекта метода перед первым аргументом.
По этим причинам первым аргументом функции в классе должен быть сам объект. Это условно называется self. Его можно назвать иначе, но мы настоятельно рекомендуем следовать правилам.
Теперь вы ознакомились с объектом класса, объектом экземпляра, объектом функции, объектом метода и их различиями.
Создание объектов
# Create an object of the class person1 = Person("Richard", 23) #Create another object of the same class person2 = Person("Anne", 30) #call member methods of the objects person1.showAge() person2.showName()
Создание объектов в Python довольно простое. Сначала вы указываете имя нового объекта, за которым следует оператор присваивания и имя класса с параметрами (как определено в конструкторе).
Помните, что количество и тип параметров должны быть совместимы с параметрами, полученными в функции-конструкторе.
Когда объект создан, могут быть вызваны методы-члены и доступны атрибуты-члены (при условии, что они доступны).
#print the name of person1 by directly accessing the ‘name’ attribute print(person1.name)
Интерфейс
В нашем классе мы реализуем программный интерфейс sklearn, а именно методы:
- fit — обучение (досл. адаптация) модели под обучающие данные
- prediсt — предсказание по определённому образцу
- score — вычислить долю верных предсказаний на определённом наборе образцов
Начало работы
Ниже приведён список всех модулей, которые нам необходимы:
Примечание. Не беспокойтесь по поводу копирования кода, в конце статьи будет ссылка на .ipynb-документ, который вы сможете изменить по своему усмотрению.
Разберёмся по порядку:
- copy.copy — т. к. наш классификатор основан на слабом ученике, то нам необходимо копировать модель, чтобы обучить новую.
- numpy — нам понадобится несколько функций из этой библиотеки. Также основой наших вычислений станет np.array.
- sklearn.datasets — отсюда мы возьмём наборы данных, на которых будем испытывать реализуемый алгоритм.
- sklearn.train_test_split — функция «разбора» набора данных на обучающую и проверочную выборки.
- sklearn.LogisticRegression — первый слабый ученик, который станет основой нашего алгоритм (название может сбить Вас с толку. Логистическая регрессия — алгоритм классификации 🙂 ).
- sklearn.neural_network — второй слабый ученик для классификатора.