Python attributeError on __del__
Asked Answered
N

2

12

I have a python class object and I want to assign the value of one class variable

class Groupclass(Workerclass):
    """worker class"""
    count = 0

    def __init__(self):
        """initialize time"""
        Groupclass.count += 1
        self.membercount = 0;
        self.members = []

    def __del__(self):
        """delte a worker data"""
        Groupclass.count -= 1


if __name__ == "__main__":
    group1 = Groupclass()

This execution result is correct, but there's an error message that says:

Exception AttributeError: "'NoneType' object has no attribute 'count'" in <bound method Groupclass.__del__ of <__main__.Groupclass instance at 0x00BA6710>> ignored

Can someone tell me what me I did wrong?

Nomenclature answered 5/8, 2013 at 12:56 Comment(5)
Your Workerclass base class appears to have a __del__ method that is trying to do something with count, but you didn't share that method here.Dramatization
sorry I don't know that's related...Nomenclature
Your message is a warning only, it is not an error. Something in the __del__ method tried to do something with the count attribute and failed.Dramatization
there's actually nothing inside __del__ except Groupclass.count -= 1. So is what bothers me because I haven't done anything yet.Nomenclature
But that is the code that generates that error message; it is rather relevant.Dramatization
D
18

Your __del__ method assumes that the class is still present by the time it is called.

This assumption is incorrect. Groupclass has already been cleared when your Python program exits and is now set to None.

Test if the global reference to the class still exists first:

def __del__(self):
    if Groupclass:
        Groupclass.count -= 1

or use type() to get the local reference:

def __del__(self):
    type(self).count -= 1

but do note that this means that the semantics for count change if Groupclass is subclassed (each subclass gets a .count attribute versus only Groupclass having a .count attribute).

Quoting from the __del__ hook documentation:

Warning: Due to the precarious circumstances under which __del__() methods are invoked, exceptions that occur during their execution are ignored, and a warning is printed to sys.stderr instead. Also, when __del__() is invoked in response to a module being deleted (e.g., when execution of the program is done), other globals referenced by the __del__() method may already have been deleted or in the process of being torn down (e.g. the import machinery shutting down). For this reason, __del__() methods should do the absolute minimum needed to maintain external invariants. Starting with version 1.5, Python guarantees that globals whose name begins with a single underscore are deleted from their module before other globals are deleted; if no other references to such globals exist, this may help in assuring that imported modules are still available at the time when the __del__() method is called.

If you are using Python 3, two additional notes apply:

  • CPython 3.3 automatically applies a randomized hash salt to the str keys used in a globals dictionary; this also affects the order in which globals are cleaned up, and it could be that you see the problem on only some of the runs.

  • CPython 3.4 no longer sets globals to None (in most cases), as per Safe Object Finalization; see PEP 442.

Dramatization answered 5/8, 2013 at 13:2 Comment(5)
Thank you it's working now. Now my question is if I want to del a Groupclass object, Groupclass object or 'Groupclass' itself must exist before the del will be executed so it seems the statement is somehow redundant?Nomenclature
@Chandler: No, when the interpreter exists, global names can be cleaned up before instances are; the Groupclass name has been cleaned up already. You can also use type(self).count instead, unless you have subclasses that do not have their own count.Dramatization
still don't quite understand about this concept but thanks I'll look into this!Nomenclature
"Starting with version 1.5, Python guarantees that globals whose name begins with a single underscore are deleted from their module before other globals are deleted; if no other references to such globals exist, this may help in assuring that imported modules are still available at the time when the __del__() method is called." Does this imply that if I rename to _Groupclass, the problem is solved?Affluent
@acai: no. It means that objects bound to names with _ at the start can count on names that do not start with _ to be deleted later, so you can still rely on imported modules (which typically have non-private names) are still available.Dramatization
A
1

When __del__() method called, the Groupclass may be recovered by the garbage collection mechanism, so using Groupclass.xxx may failed. But you can access the count variable through self.__class__.count. Code likes below:

def __del__(self):
    self.__class__.count -= 1
Antifriction answered 28/4, 2020 at 6:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.