Izaya
Izaya

Reputation: 1548

Delete object instance from class function in python

I would like to delete an instance of my object after executing a function so that no python script can access this instance anymore.

Here is my code:

class MyClass():
    def myFunc(self):
       ...
       del self

myClass = MyClass()
myClass.myFunc()
print(myClass) # Supposed to raise an error because myClass is supposed to be deleted but that's not the case

What's going wrong?

Upvotes: 1

Views: 2844

Answers (2)

Maxim
Maxim

Reputation: 286

Since you can't delete objects in python and only delete the appearance of variables in the namespace. I would recommend just raising an error once the function is called once. Since you want an error to occur after its run.

class MyClass():
   def myFunc(self):
      ...
      counter += 1
      del self

counter = 0
# Check if the function has been run once and then raise exception
if counter > 0:
    raise exception("Instance cannot be used")

myClass = MyClass()
myClass.myFunc()
print(myClass)

I hope this still does what you anticipate but the del function only deletes the appearance of variable in the namespace and not allowing you to reference it anymore (But its not being deleted).

Upvotes: 1

Mad Physicist
Mad Physicist

Reputation: 114240

You misunderstood how del works. It does not remove objects. It removes names.

For example, say you have

>>> x = [1, 2, 3]
>>> y = x
>>> z = x

All three names, x, y, z refer to the same list object. Now delete x:

>>> del x
>>> x
NameError: name 'x' is not defined

It would make no sense for y and z to raise a NameError after this. Imagine especially if y and z were references in a different function or module. Having del x make other references disappear would lead to some very unexpected and undesirable behaviors.

So under normal circumstances, you can't quite do what you want to do. Your current method is just removing the name self in the local namespace of the method itself. It can not easily modify the global namespace.

That being said, you can write a function that removes a name from the global namespace. For example:

class MyClass:
    def myFunc(self, name):
        del globals()[name]

myInst = MyClass()
myInst.myFunc('myInst')

Now, if you attempt to access myInst, the name will be gone in the script. This is a bad idea, and likely won't delete the object at all anyway. If you had another reference to myInst, e.g. in a list, dict or direct assignment to another name, that reference would persist, and so would the object itself.

A much better approach, as suggested in the comments, is to mark the instance as unusable. For example, you can do something like

class MyClass:
    def __init__(self):
        self.useable = True

    def my_func(self):
        self._check_useable()

        # do your thing...

        self.useable = False

    def other_func(self, *args):
        self._check_useable()
        # Do stuff to args ...

    def _check_useable(self):
        if not self.useable:
            raise ValueError('Class is not useable!')

There are more robust ways of implementing the flag to make it less accessible to the casual user, but they basically follow the same pattern.

Upvotes: 2

Related Questions