user1876508
user1876508

Reputation: 13172

AttributeError when running Python

When running my program that makes the function call

self.getFileButton = Button(self,
                            text = "...",
                            command =
                            tkFileDialog.askopenfilename(mode="r+b", **self.file_opt))

I get the error

File "C:/Documents and Settings/l/My Documents/Python/csv_GUI.py", line 33, in create_widgets
tkFileDialog.askopenfilename(mode="r+b", **self.file_opt))

AttributeError: selectFile instance has no attribute 'file_opt'

Upvotes: 2

Views: 267

Answers (3)

Nicola Lamacchia
Nicola Lamacchia

Reputation: 23

I think that, generally speaking, you should avoid to pass arguments to the callback function in the Button function itself (using lambdas), it's ugly and it's not pythonic.

Do something like this instead:

def __init__(self, ...):
    ...
    Tkinter.Button(self, text='...', command=self.openfile).pack(...)
    ...

def openfile(self):
    return tkFileDialog.askopenfile(mode='r+b', **self.file_opt)

just to give the idea...

Upvotes: 1

abarnert
abarnert

Reputation: 365915

Do you actually have a file_opt member defined in, e.g., your __init__ method, or elsewhere?

If the problem is that you are defining one, but not until after you've done the getFileButton, can you just rearrange the order? If not, mgilson's solution is the right one. But otherwise, it's much simpler.

And if you don't have a file_opt member anywhere, it's even simpler: Don't try to pass something that doesn't exist.

Upvotes: 2

mgilson
mgilson

Reputation: 310049

You probably want something like:

self.getFileButton = Button(self,
                            text = "...",
                            command = lambda: tkFileDialog.askopenfilename(mode="r+b", **self.file_opt))

The problem is that as you wrote it, the askopenfilename function gets run when the button is created (not when clicked). Based on the AttributeError, you create the button before you create the file_opt mapping, but, assuming that the file_opt attribute exists when you click the button, this should defer that lookup (and function call) until an appropriate time.

Basically, lambda just creates a new function:

foo = lambda x : x*x

is equivalent* to:

 def foo(x):
     return x*x

Written this way, it's easy to see why we defer calling the askopenfilename function until the button actually gets clicked.

*There are a few cases where a lambda function behaves differently than a regular function, but we don't have to worry about those for the purposes of this post.

Upvotes: 7

Related Questions