简体   繁体   中英

What is the difference between `__del__` and `__delete__`?

Suppose someone didn't know what the difference was between __del__ and __delete__ ? Write an explanation.

object.__del__(self) :

Called when the instance is about to be destroyed. This is also called a finalizer or (improperly) a destructor. If a base class has a __del__() method, the derived class's __del__() method, if any, must explicitly call it to ensure proper deletion of the base class part of the instance.

I think this means that my_object.__del__ will get called by CPython's garbage collector after the reference count for my_object drops to zero.

object.__delete__(self, instance) :

Called to delete the attribute on an instance instance of the owner class.

The __delete__ dunder method is related to python's notion of descriptors ; a descriptor is "any object which defines the methods __get__() , __set__() , or __delete__() ." Descriptors can be used to implement custom behavior for attribute lookup/assignment/deletion (via __get__ / __set__ / __delete__ , respectively).

See also:

  • The del statement : "Deletion of a name removes the binding of that name from the local or global namespace... Deletion of attribute references, subscriptions and slicings is passed to the primary object involved..."
  • The delattr built-in function. From the docs, "The function deletes the named attribute, provided the object allows it. For example, delattr(x, 'foobar') is equivalent to del x.foobar ."
  • object.__delattr__(self, name) is called when attribute deletion is attempted. According to the docs, "This should only be implemented if del obj.name is meaningful for the object." Thus, defining a user class with the method MyClass.__delattr__ enables custom behavior when eg the statement del my_object.an_attr is invoked, or (equivalently) when delattr(my_object, 'an_attr') is called.
  • object.__delitem__(self, key) is "Called to implement deletion of self[key] ." Thus, defining a user class with the method MyClass.__delitem__ enables custom behavior when eg the statement del my_object[a_key] is invoked.

__del__ is called when you delete an object and __delete__ is sometimes called when you delete an attribute of an object.

del x.my_num    # __delete__
del x           # __del__            

ABOUT __del__:

The following code shows when __del__ gets called:

class MyClass:
    def __init__(self):
        file = open("really_cool_file.txt", "w+")
        self._f = file

    def __del__(self):
        print("closing any open files ")
        self._f.close()

my_instance = MyClass()
del my_instance

If my_instance is the last label pointing to the data, then del my_instance calls MyClass.__del__(my_instance)

Technically, del my_instance only deletes the label my_instance . Imagine people at a party all wearing names tags. Sometimes a person has 6 or 7 names tags on simultaneously, and other times, they only have one. Python will kick anyone out of the party who is not wearing at least one name tag. MyClass.__del__(my_instance) gets called when the last name-tag/label is removed from a piece of data.

The code above shows an example of when we make sure to close an open file. Another example might be to count of the number active instances of a given class:

class Klass:
    count = 0
    # `count` belongs to the class
    # instances do not each get their own copy of `count`
    def __init__(self):
        type(self).count += 1
        self.instance_var = "I belong to instances"
    def __del__(self):
        type(self).count -= 1
obj = Klass()
print(obj.count)

ABOUT __delete__

Unlike __del__ , __delete__ has to do with descriptors. The code below describes the behavior of obj.my_var or getattr(obj, “my_var”)

class Klaus: def getattribute (self, attrname): try: attribute = attrname from instance Klaus except AttributeError: attribute = attrname from class Klaus

    # Begin code for handling "descriptors"
    if hasattr(attribute, '__get__'):
        attr = attribute.__get__(self, Klaus)
    # End code for handling "descriptors"

    return attribute

If my_var is a descriptor, then following two lines of code equivalent:

x = obj.my_var
x = Klass.my_var.__get__(obj, "my_var")

Just as __getattribute__ checks whether the attribute has a __get__ method or not, __delattr__ will check whether the attribute has a __delete__ method or not.

def __delattr__(self, name):
    attribute = getattr(self, name)
    if hasattr(attribute, "__delete__"):
       attribute.__delete__(self)
    else:
       del self.__dict__[name]

You can see when __delete__ gets called by viewing the following code:

class desc:
    def __delete__(descriptor, instance_of_Klaus):
        print("attribute was deleted")

class Klaus:
    d = desc()
    def __init__(self):
        pass

my_instance = Klaus()
del my_instance.d

When dealing with descriptors, the following lines of code are all equivalent:

del my_instance.d
delattr(my_instance, "d")
Klaus.d.__delete__(my_instance)

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