быть следующим кодом простого приложения в kivy:
from kivy.config import Config
Config.set('kivy', 'keyboard_mode', 'system')
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.properties import StringProperty
Builder.load_file('design2.kv')
class MyWidget(BoxLayout):
def __init__(self):
super(MyWidget, self).__init__()
self.showtext() #Llamamos al método desde el constructor
def showtext(self):
with open("Prueba.txt","r") as f:
self.ids['Label1'].text = f.read()
class myApp(App):
def build(self):
return MyWidget()
def on_pause(self):
return True
def on_resume(self):
pass
if __name__ in ('__main__', '__android__'):
myApp().run()
Пусть файл .kv будет (здесь это не актуально):
<MyWidget>:
BoxLayout:
Label:
id: Label1
Меня интересует следующий фрагмент кода из первого кода:
class MyWidget(BoxLayout):
def __init__(self):
super(MyWidget, self).__init__()
self.showtext() #Llamamos al método desde el constructor
Насколько я понимаю, def __init__(self):
это конструктор. Для чего нужен конструктор? Другой вопрос касается строки: super(MyWidget, self).__init__()
Что такое super
?
Вопрос на самом деле не специфичен для Kivy, а для Python и парадигмы ООП (объектно-ориентированного программирования) в целом.
Короткий ответ: хотя этот метод
__init__
иногда называют «конструктором», на самом деле это просто инициализатор экземпляра, обычно он используется для инициализации атрибутов создаваемого нами объекта и выполняется автоматически, как только создается экземпляр класса. В вашем случае, поскольку мы вызываем метод внутри него,showtext
текст уже загружен в метку при запуске нашего приложения.super
в данном случае используется для вызова инициализатора родительского классаBoxLayout
. В этом случае он эквивалентенBoxLayout.__init__(self, *args, **kwargs)
.Длинный ответ приведен ниже, все они ориентированы на Python 3, хотя все они применимы к классам нового стиля Python 2 (явно производным от
object
):Строго говоря, термин «конструктор» в Python может быть несколько двусмысленным. Когда мы создаем объект, задействованы два специальных метода, первое, что вызывается, это метод,
__new__
а затем вызывается метод__init__
:__new__
: в основном он возвращает действительный экземпляр класса. Он только создает объект своего класса и возвращает его, поэтому его следует считать истинным «конструктором» класса. Получает ссылку на класс в качестве первого аргумента (cls
).Переопределение этого метода встречается не так часто, как в случае с
__init__
, как правило, его использование заключается в настройке инстанцирования класса, например, это один из способов создания синглтона:Если мы переопределяем метод, мы должны получить новый экземпляр, вызвав
__new__
родительский метод (который исходит из класса,object
от которого происходят все классы нового стиля ), например:__init__
: если он__new__
возвращает экземпляр своего класса (обычно), то метод__init__
, которому он передает вновь созданный экземпляр в качестве первого аргумента (self
по соглашению), выполняется неявно. Если__new__
он не возвращает экземпляр класса, он не вызывается и должен выполняться явно. Некоторые из его особенностей:Во многих языках оба метода объединены в один и он рассматривается как конструктор. Вы можете найти диалектические споры по этому поводу, существует важная тенденция вызывать конструктор
__init__
, хотя это и не совсем правильно.Основная цель
__init__
состоит в том, чтобы инициализировать атрибуты объекта, который мы создаем:В
__init__
этом случае создается и инициализируется атрибут экземпляраradio
, свойство каждого объектаCírculo
, которое отличает его от других кругов.Мы можем создать атрибут снаружи
__init__
или любой метод, как вы могли заметить, какpi
в примере выше. В обоих случаях есть существенная разница: атрибутpi
— это атрибут, который принадлежит классу и является общим для всех созданных нами экземпляров класса.radio
вместо этого он создается__init__
для экземпляра, он принадлежит исключительно объекту, инициализируя его, придавая ему отличительные свойства. Для получения дополнительной информации может быть полезен следующий вопрос:Разница между атрибутами экземпляра и атрибутами класса
Теперь, чтобы закончить, поговорим о
super
том, что обычно используется в инициализаторе класса, как в показанном вами примере. Это связано с тем, что определение нашего собственного инициализатора переопределяет инициализатор__init__
родительского класса. Поэтому, чтобы наш класс наследовал все функции своего родителя, реализованные в его инициализаторе (который мы переопределили), необходимо вызвать его явно. Это именно то, о чем он заботитсяsuper(MyWidget, self).__init__()
.В общем, он допускает явную ссылку на родительский класс , поэтому позволяет делегировать вызов метода родительскому классу (или классам).
Вылет из:
В случаях множественного наследования именно здесь у него
super
есть свой истинный потенциал, поскольку он будет искать метод среди родительских классов в определенном порядке (порядок разрешения методов ), но это уже далеко от вопроса.