Почему вы не можете вызвать атрибуты объекта в __init__? - PullRequest
0 голосов
/ 08 февраля 2020

Я пытаюсь понять, почему вы можете вызывать атрибут объекта в методе класса, но не в его конструкторе. Например:

class Panel1(wx.Panel):

    #include Frame in the constructor
    def __init__(self, parent, frame):
        wx.Panel.__init__(self, parent)
        #set up so objects assigned in Frame (and it's children) can be called
        self.frame = frame
        button = wx.Button(self, label='Test')
        #button.Bind(wx.EVT_BUTTON, lambda event: self.onButton(event))
        button.Bind(wx.EVT_BUTTON, self.onButton)

        pprint(vars(self.frame))


    def onButton(self, event):
        print("Button pressed.")
        pprint(vars(self.frame))
        #the following fails in the constructor as panel2 for some reason is not callable
        a = self.frame.panel2.a
        print("123: " + str(a))

Может кто-нибудь указать мне ссылку, которая объясняет, почему это не возможно в конструкторе?

Спасибо!

***** РЕДАКТИРОВАТЬ ****

Ниже приведен функциональный код, который поможет лучше объяснить мой вопрос. Если вы попытаетесь вызвать атрибуты Panel2 через родительский элемент в конструкторе Panel1, произойдет сбой. Но он работает нормально, когда выполняется внутри метода onButton Panel1. Я хотел бы понять, почему.

import wx
from pprint import pprint

class Panel1(wx.Panel):

    #include Frame in the constructor
    def __init__(self, parent, frame):
        wx.Panel.__init__(self, parent)

        self.frame = frame
        self.strPanel1 = "Panel1 string"
        self.intPanel1 = 0

        button = wx.Button(self, label='Test')
        button.Bind(wx.EVT_BUTTON, self.onButton)

        self.textbox = wx.TextCtrl(self)

        sizer = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(sizer)
        sizer.Add(self.textbox, 0, wx.ALL, 5)
        sizer.Add(button, 0, wx.ALL, 5)
        #pprint self.frame attributes fail here

    def onButton(self, event):
        #but not here!?!
        print("Panel1 button pressed.")
        pprint(vars(self.frame))
        Panel2str = self.frame.panel2.strPanel2
        print(Panel2str)
        Panel2int = self.frame.panel2.intPanel2
        print(str(Panel2int))
        #Panel2 button press counter
        self.frame.panel2.intPanel2 += 1
        self.frame.panel2.trigger()

    def trigger(self):
        print("Panel1 has been triggered")

class Panel2(wx.Panel):

    #include Frame in the constructor
    def __init__(self, parent, frame):
        wx.Panel.__init__(self, parent)

        self.frame = frame
        self.strPanel2 = "Panel2 string"
        self.intPanel2 = 0

        button = wx.Button(self, label='Test')
        button.Bind(wx.EVT_BUTTON, self.onButton)

        self.textbox = wx.TextCtrl(self)

        sizer = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(sizer)
        sizer.Add(self.textbox, 0, wx.ALL, 5)
        sizer.Add(button, 0, wx.ALL, 5)
        #pprint self.frame attributes fail here

    def onButton(self, event):
        #but not here!?!
        print("Panel2 button pressed.")
        pprint(vars(self.frame))
        Panel1str = self.frame.panel1.strPanel1
        print(Panel1str)
        Panel1int = self.frame.panel1.intPanel1
        print(str(Panel1int))
        #Panel1 button press counter
        self.frame.panel1.intPanel1 += 1
        self.frame.panel1.trigger()

    def trigger(self):
        print("Panel2 has been triggered")

class Frame(wx.Frame):

    def __init__(self):
        wx.Frame.__init__(self, None, title="My Frame")

        #Spliiting the frame
        splitter = wx.SplitterWindow(self)

        #Send frame to children
        self.panel1 = Panel1(splitter, self)
        self.panel2 = Panel2(splitter, self) 

        splitter.SplitVertically(self.panel1, self.panel2, 0)
        splitter.SetMinimumPaneSize(200)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(splitter, 1, wx.EXPAND)

        self.SetSizer(sizer)


if __name__ == '__main__':
    app = wx.App()
    frame = Frame()
    frame.Show()
    frame.Centre()
    app.MainLoop()

1 Ответ

0 голосов
/ 09 февраля 2020

Ниже приведен функциональный код, который поможет лучше объяснить мой вопрос. Если вы попытаетесь вызвать атрибуты Panel2 через родительский элемент в конструкторе Panel1, произойдет сбой.

Сбой, поскольку в момент вызова вашего Panel1.__init__, frame.panel2 еще не установлен. Посмотрите на ваш Frame класс:

class Frame(wx.Frame):

    def __init__(self):
        wx.Frame.__init__(self, None, title="My Frame")

        #Spliiting the frame
        splitter = wx.SplitterWindow(self)

        #Send frame to children
        self.panel1 = Panel1(splitter, self)
        self.panel2 = Panel2(splitter, self)

        ...

Когда ваш Panel1 инициализирован, panel2 еще не установлен. Он будет установлен только после завершения инициализации Panel1 и присвоения frame.panel1. Если вам абсолютно необходимо получить доступ к panel2 в Panel1.__init__, то вы можете сделать так, чтобы ваш Panel1 позаботился об этом. Например:

class Panel1:
    def __init__(self, frame):
        # Initialize panel2 and assign it to our frame
        frame.panel2 = Panel2(frame)

        # Now we can do whatever with panel2
        frame.panel2

class Panel2:
    def __init__(self, frame):
        pass

class Frame:
    def __init__(self):
        # This initialize panel1, and internally initialize panel2
        self.panel1 = Panel1(self)


frame = Frame()
...