user3595184
user3595184

Reputation: 251

Why am I getting "NameError: global name 'open' is not defined" in __del__?

I'm getting a NameError in the __del__ function of a class. I do not understand why 'open' is not accessible inside the function __del__. I am using Python 3.4.0

Python Code:

class Contoller:

    ...

    def __del__(self):
        store = {}
        ...
        pickle.dump(store, open('data.p', 'wb'))    

class MyWindow(Gtk.Window):

    def __init__(self):
        ...
        self.controller = Contoller(self)
        ...
        self.connect("delete-event", self.quit)
        ...

    ...

    def quit(self, widget, event):
        del self.controller
        Gtk.main_quit()

Error Message:

Traceback (most recent call last):
  File "main.py", line 69, in __del__
NameError: name 'open' is not defined

Upvotes: 25

Views: 17762

Answers (3)

Quip11
Quip11

Reputation: 194

user3595184's code used to work until Python 3.4. I know because I've just run into the same issue, calling open() within __del__. Apparently built-in functions no longer work, because of a change in when __del__ is run as the interpreter shuts down.

UPDATE: See https://docs.python.org/3/library/weakref.html, especially the section on finalizers. I have several classes that encapsulate access to resources that had __del__() methods to unlock or clean up as soon as the application would exit, for any reason. Catching all exceptions or exits at the application level and explicitly calling cleanup methods is inconvenient and bug-prone. I'll try using a local finalizer instead.

UPDATE: I'm having better luck with __enter__() and __exit__(), putting the top-level object in a with clause. It appears at least the __exit__() gets called no matter how, so I can call the cleanup methods (__exit__()'s themselves) of all subordinate objects. That's working for me.

Upvotes: 13

antont
antont

Reputation: 2756

It is generally not a good idea to rely on __del__ for anything in Python.

Better use a normal method and call it, self.controller.store() or whatever name you find best.

Related discussion is for example in I don't understand this python __del__ behaviour

UPDATE: atexit.register may be what you want, https://docs.python.org/2/library/atexit.html . As featured in this nice article at "Common Mistake #10: Misusing the __del__ method" http://www.toptal.com/python/top-10-mistakes-that-python-programmers-make

As for the explanation, this discussion tells: "At interpreter shutdown, the module's global variables are set to None before the module itself is released." -- perhaps that applies to builtins too, http://bugs.python.org/issue5099

Upvotes: 4

kangaswad
kangaswad

Reputation: 775

I think it just a scope problem.

self.controller = Contoller(self)

I don't know why you should pass MyWindow class as argument when initiating Controller class. Try to change it to:

self.controller = Contoller()

Upvotes: -3

Related Questions