2

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?

3
  • 2
    "I could fix the warning by adding 8 definition lines assigning None to all the variables"... that is what the warning is telling you to do. In general having attributes suddenly appear on an object that weren't defined in the __init__ method can make debugging more difficult. Commented Sep 26, 2017 at 19:38
  • also, this is pretty highly dependent on the linter you're using. Commented Sep 26, 2017 at 19:39
  • @turbulencetoo I use pycharm Commented Sep 26, 2017 at 20:02

2 Answers 2

5

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()
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks my problem was with not adding width, height, entries = kwargs.pop('width'), kwargs.pop('height'), kwargs.pop('entries')! I didn't know what kwargs are and I was getting errors bc of that. thank you.
3

I would also add that as of python 3.3, this also hints about missing an optimization feature for each instance’s __dict__ when any attribute is set outside of the __init__ method.

As stated in Fluent Python 2nd Edition, Chapter 3, page 103:

Python’s default behavior is to store instance attributes in a special __dict__ attribute, which is a dict attached to each instance. Since PEP 412—Key-Sharing Dictionary was implemented in Python 3.3, instances of a class can share a common hash table, stored with the class. That common hash table is shared by the __dict__ of each new instance that has the same attributes names as the first instance of that class when __init__ returns. Each instance __dict__ can then hold only its own attribute values as a simple array of pointers. Adding an instance attribute after __init__ forces Python to create a new hash table just for the __dict__ of that one instance (which was the default behavior for all instances before Python 3.3). According to PEP 412, this opti‐ mization reduces memory use by 10% to 20% for object-oriented programs.

There’s further explanation of the internal optimizations at FluentPython: Internals of sets and dicts

1 Comment

@MSeifert, the problem when initialising attributes with None within the __init__ method is that it requires annotating both the usual type of the attribute and the None type. This increases the job of type checkers like pyright, plus it requires much more boilerplate code to handle sometimes inexistent cases where the attribute is None (if self.attribute is None). At the same time, it often happens to me that all my attributes are not None at the end of the __init__ execution. What do you think? @radyz @yukashima

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.