Adam Mitchell Adam Mitchell - 2 months ago 13
Python Question

Tkinter .withdraw() strange behaviour

Using the following code, the Tkinter root window will be hidden:

def main():
root = Tkinter.Tk()
root.iconify()
a = open(tkFileDialog.askopenfilename(), 'r')

main()


However, using this variation, the root window will not be hidden:

class Comparison:
def __init__(self, file=open(tkFileDialog.askopenfilename(),'r')):
self.file = file
self.length = sum(1 for _ in self.file)

def main():
root = Tkinter.Tk()
root.iconify()
a = Comparison()

main()


Why does calling
tkFileDialog.askopenfilename
with the constructor cause this behaviour? I have tried both
root.withdraw()
and
root.iconify()
and experienced the same behaviour.

It may be worth noting that I am on OSX 10.11.6.

Thanks!

Answer

When you do this:

def __init__(self, file=open(tkFileDialog.askopenfilename(),'r')):

That immediately runs open(tkFileDialog.askopenfilename(),'r'), because default arguments are evaluated when the function is defined. Therefore, when you run the second code block, the interpreter creates a necessary Tkinter root window and opens that file chooser while it's still defining that class. After that, you define a function main. Finally, you call main(), which creates a root object, withdraws it, and instantiates an object of the Comparison class. The root window you explicitly created with root = Tkinter.Tk() is hidden. The older one, that Python was forced to create in order for the file dialog to exist, however, was not.

To fix this, put the default behavior into the method body rather than its signature:

class Comparison:
    def __init__(self, file=None):
        if file is None:
            self.file = open(tkFileDialog.askopenfilename(),'r')
        else:
            self.file = file
        self.length = sum(1 for _ in self.file)