Причина для себя при расширении объектов (Python)

Итак, скажем, я расширяю объект с именем Frame (найденный в «tkinter»), как показано ниже,

class GraphRegion(Frame):

    def __init__(self, master):
        Frame.__init__(self,master)

Теперь я знаю, зачем нужен «мастер». Зачем Frame.__init__ нужен 'self'? Разве «я» не указывает на GraphRegion? Что это на самом деле говорит объекту «Frame»? Это создать GraphRegion как тип «Frame»?


person gnasr    schedule 03.08.2014    source источник


Ответы (2)


Хотя ответ Мартджина великолепен, я собираюсь расширить его в некоторых, скажем, терминах «более низкого уровня».

По сути, всякий раз, когда вы создаете новый объект GraphRegion (myobject = GraphRegion(master)), __init__ вызывается с новым объектом в качестве первого параметра (self) и аргументом master в качестве второго параметра.

В принципе, если вы сделаете это:

myobject = GraphRegion(master)

__init__ get вызывается так:

__init__(myobject, master)

Это связано с тем, что вы часто хотите присвоить свойства конкретным экземплярам объекта, и self позволяет вам это сделать. Например, если бы у меня был класс Movie, где у каждого экземпляра был бы собственный заголовок, я бы использовал self следующим образом:

class Movie(object):
    def __init__(self, title):
        self.title = title

Таким образом, каждый экземпляр Movie может иметь собственный заголовок.

Теперь всякий раз, когда вы запускаете Frame.__init__(self, master), этой функции __init__ часто требуется модифицировать конкретный экземпляр класса GraphRegion, который вы создаете (объект, который вы создаете), и self является этим экземпляром, поэтому вы передаете его методу __init__.

person Thomas Hobohm    schedule 03.08.2014
comment
Итак, скажем, тогда я должен был добавить к нему виджет, например, если бы я добавил 'self.labelYEQUALS=Label(self)' в инициализацию. Дай мне посмотреть, понимаю ли я это. «Я» передается в «главную» переменную. Передача «я» в эту метку является передачей текущего экземпляра GraphRegion, поэтому мастер экземпляра GraphRegion является мастером созданной мной метки. Это правильно? - person gnasr; 03.08.2014
comment
Подумайте об этом так: класс Frame имеет собственный метод __init__, который, вероятно, выглядит примерно так: def __init__(self, master, ...). Таким образом, когда вы вызываете Frame.__init__(self, master), вы в основном просто вызываете этот метод __init__, при этом параметр master является мастером вашего экземпляра GraphRegion. Мастером созданного вами Label является ваш экземпляр GraphRegion, а мастером GraphRegion является все, что вы передали в функцию __init__ при ее создании. - person Thomas Hobohm; 03.08.2014

Потому что Frame.__init__ — это несвязанный метод.

Только поиск методов в экземплярах дает связанный метод, есть экземпляр для привязки self к. Поскольку Frame.__init__ не привязан, вам нужно явно передать первый аргумент, экземпляр.

Вы не можете иначе получить доступ к этому методу; self.__init__ GraphRegion.__init__ привязан к self. Поэтому, если вы хотите повторно использовать версию Frame.__init__, вам нужно пойти и запросить ее у Frame напрямую.

По сути, при создании нового экземпляра, скажем, с `GraphRegion(application) Python делает следующее:

  1. Python создает новый пустой экземпляр для класса GraphRegion, назовем его временным именем new.
  2. Python хочет инициализировать экземпляр, поэтому вызывает new.__init__(application).
  3. Ищется атрибут __init__. Он не найден в самом экземпляре, поэтому Python затем смотрит на класс.
  4. __init__ находится в классе. При поиске атрибутов в классе, если атрибут поддерживает протокол дескриптора, выполняется дополнительный шаг: binding. __init__ привязывается к экземпляру, создавая привязанный метод.
  5. Python вызывает связанный метод, передавая application.
  6. Связанный метод вызывает фактическую функцию __init__, передавая new (экземпляр) и application.
  7. Теперь внутри GraphRegion.__init__ у вас есть как self (экземпляр new), так и master (привязанный к тому же объекту, к которому был привязан application), но вам также нужно вызвать метод Frame.__init__.
  8. Поиск __init__ в Frame происходит непосредственно в классе, поэтому протокол дескриптора не имеет экземпляра для привязки. Возвращается несвязанный метод.
  9. Вызов метода Frame.__init__ не может передать связанный экземпляр. Вам нужно передать его явно.

При использовании классов нового стиля для доступа к < em>bound для суперклассов. Для Tkinter.Frame, который работает только в Python 3, в Python 2 весь модуль Tkinter по-прежнему использует классы старого стиля.

Для Python 3 это будет выглядеть так:

class GraphRegion(Frame):
    def __init__(self, master):
        super().__init__(master)

Но, как уже говорилось, в Python 2 при использовании Tkinter единственный вариант — напрямую ссылаться на несвязанный метод, полученный непосредственно из класса Frame.

person Martijn Pieters    schedule 03.08.2014