简体   繁体   中英

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'

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.

Do you actually have a file_opt member defined in, eg, 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.

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...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM