Search code examples
pythonarchitectureinitializationdefinition

Python - instance attribute defined outside __init__()


I get the warning in question for the following code:

from tkinter import *
from tkinter import ttk


class Autocomplete(Frame, object):
    def __init__(self, *args, **kwargs):
        super(Autocomplete, self).__init__(*args, **kwargs)
        self.list = []

    def build(self, width, height, entries):
        # I get the warning for the following 8 lines:
        self._entries = entries
        self.listbox_height = height
        self.entry_width = width
        self.text = StringVar()
        self.entry = ttk.Entry(self, textvariable=self.text, width=self.entry_width)
        self.frame = Frame(self)
        self.listbox = Listbox(self.frame, height=self.listbox_height, width=self.entry_width)
        self.dropdown = Listbox(self.frame, height=self.listbox_height, width=self.entry_width, background="#cfeff9",
                                takefocus=0)
        self.entry.pack()
        self.frame.pack()
        self.listbox.grid(column=0, row=0, sticky=N)
        self.dropdown.grid(column=0, row=0, sticky=N)
        self.dropdown.grid_forget()
        return self
root = Frame(Tk())
autocomplete = Autocomplete(root).build(74, 10, entries)
root.pack()
autocomplete.pack()
mainloop()

How should I fix this? I tried to move everything to init but then I had some errors for passing the arguments in the line I was creating the Autocompelete object. So please provide me with all the changes I have to make. not just smth like you have to move them. I could fix the warning by adding 8 definition lines assigning None to all the variables but I think that's such a stupid solution. So what is the right thing to do?


Solution

  • It's always important to keep in mind that not all Warnings require fixing. Warnings are just Warnings. They are supposed to point out a specific part of the code because it's a "common" source of problems. But sometimes you need/want to do it that way.

    I could fix the warning by adding 8 definition lines assigning None to all the variables

    That's just "silencing" the Warnings, in my opinion that's just as good as ignoring the Warnings.

    So what is the right thing to do?

    The right way would be to just use __init__. I did a quick test and I don't have any problems.

    However that's just an example how one could do it. I haven't checked what Frame wants as arguments for __init__ so it could lead to conflicts:

    from tkinter import *
    from tkinter import ttk
    
    class Autocomplete(Frame, object):
        def __init__(self, *args, **kwargs):
            width, height, entries = kwargs.pop('width'), kwargs.pop('height'), kwargs.pop('entries')
            super(Autocomplete, self).__init__(*args, **kwargs)
            self.list = []
            self._entries = entries
            self.listbox_height = height
            self.entry_width = width
            self.text = StringVar()
            self.entry = ttk.Entry(self, textvariable=self.text, width=self.entry_width)
            self.frame = Frame(self)
            self.listbox = Listbox(self.frame, height=self.listbox_height, width=self.entry_width)
            self.dropdown = Listbox(self.frame, height=self.listbox_height, width=self.entry_width, background="#cfeff9",
                                    takefocus=0)
            self.entry.pack()
            self.frame.pack()
            self.listbox.grid(column=0, row=0, sticky=N)
            self.dropdown.grid(column=0, row=0, sticky=N)
            self.dropdown.grid_forget()
    
    root = Frame(Tk())
    autocomplete = Autocomplete(root, width=74, height=10, entries=entries)
    root.pack()
    autocomplete.pack()
    mainloop()