user2992997
user2992997

Reputation: 667

How to delete an instantiated object Python?

I am relatively new to object oriented programming and I cannot figure out how to delete an instantiated object in Python.

if self.hit_paddle(pos) == True or self.hit_paddle2(pos) == True:
    bar = bar + 1
if bar == 1:
    global barbox1
    barbox1 = barfill(canvas)
    barbox1.canvas.move(barbox1.id, 253, 367)
if bar == 2:
    global barbox2
    barbox2 = barfill(canvas)
    barbox2.canvas.move(barbox5.id, 413, 367)
    bar = 0
    time.sleep(0.2)
    barbox1 = None
    barbox2 = None

That is the code, the main thing I was trying in order to delete the objects was barbox1 = None, but that doesn't seem to work.

Upvotes: 57

Views: 194317

Answers (6)

catasaurus
catasaurus

Reputation: 966

An object in python is created by storing a memory address that points to the object. Example:

class SomeObject():
  def __init__(self, something, something_else):
    self.something = something
    self.something_else = something_else
  def some_method(self):
    return str(self.something)

a_variable_holding_a_memory_address = SomeObject(something=94, something_else=243)
a = a_variable_holding_a_memory_address
print(id(a) == id(a_variable_holding_a_memory_address))

Output:

True

If you don't know, id() returns the memory address of a variable in python. Thus if you delete a_variable_holding_a_memory_address:

class SomeObject():
  def __init__(self, something, something_else):
    self.something = something
    self.something_else = something_else
  def some_method(self):
    return str(self.something)

a_variable_holding_a_memory_address = SomeObject(something=94, something_else=243)
a = a_variable_holding_a_memory_address
print(a_variable_holding_a_memory_address)
del a_variable_holding_a_memory_address
print(a)

Output:

<__main__.SomeObject object at 0x7f80787ea940>
<__main__.SomeObject object at 0x7f80787ea940>

All that happened was a variable holding the memory address of an object (or a reference) was deleted, but the address itself was not as another reference to it exists. Now look at this:

# In this example I use ctypes to print out the value at a memory address

import ctypes

class SomeObject():
  def __init__(self, something, something_else):
    self.something = something
    self.something_else = something_else
  def some_method(self):
    return str(self.something)

a_variable_holding_a_memory_address = SomeObject(something=94, something_else=243)
a = a_variable_holding_a_memory_address

# print out the value at the memory address that a_variable_holding_a_memory_address holds
object_id = id(a_variable_holding_a_memory_address)
print(ctypes.cast(object_id, ctypes.py_object).value)

del a_variable_holding_a_memory_address

# now lets try it when only one of the references is deleted
print(ctypes.cast(object_id, ctypes.py_object).value)

del a

# the same thing but when both of the references are deleted
print(ctypes.cast(object_id, ctypes.py_object).value)

Output:

<__main__.SomeObject object at 0x7fbd04b5d3a0>
<__main__.SomeObject object at 0x7fbd04b5d3a0>
<__main__.SomeObject object at 0x7fbd04b5d3a0>
zsh: segmentation fault  python file.py

This segmentation fault happened because the program tried to reference an empty memory address.

This is one of the advantages of using a language of python versus c because it prevents this type of memory error unless you really try to make the program crash like in this example. This includes automatic garbage collection (a part of the python interpreter that frees up memory by emptying unused memory addresses).

But you see, when both of the references existed the memory address held an object. When one is deleted the address is not because there still exists one reference to the address. That is the automatic garbage collector at work. When both of them are deleted the address is too, thus the error. It should also be noted that simply assigning a different value to a variable like so:

a = "I now hold a str object"

Instead of:

del a

works too because the reference to the object is replaced with a reference to another object, thus one less reference.

This not only happens for user defined objects, but for very basic objects that come with python, often taken for granted, like str or int or list or dict, the list goes on. In the end, thats what variables hold in python, an object. Unless it holds a boolean like True or False or None. But those are objects too. Python docs for None:

An object frequently used to represent the absence of a value, as when default arguments are not passed to a function. Assignments to None are illegal and raise a SyntaxError. None is the sole instance of the NoneType type.

Reference count:

The reference count to an object in python is the amount of variables holding a reference to the object. When that count reached zero, __del__ is called of the object is called and it is destroyed (unless __del__ does the following as outlined in the docs:

It is possible (though not recommended!) for the del() method to postpone destruction of the instance by creating a new reference to it. This is called object resurrection. It is implementation-dependent whether del() is called a second time when a resurrected object is about to be destroyed; the current CPython implementation only calls it once. )

If you want a reference to an object that does not keep the object alive, there is a type of reference called a weakref:

import weakref

class SomeObject():
  def __init__(self, something, something_else):
    self.something = something
    self.something_else = something_else
  def some_method(self):
    return str(self.something)

reference = SomeObject('something', 'something_else')

print(reference)

weak_reference = weakref.ref(reference)

print(weak_reference)

del reference

print(weak_reference)

Output:

<__main__.SomeObject object at 0x7f305b017880>
<weakref at 0x7f305ae7c630; to 'SomeObject' at 0x7f305b017880>
<weakref at 0x7f305ae7c630; dead>

The weakref, weakreference becomes a reference to nothing, a dead object.

Circling back the garbage collection, by using the gc built in library you can change some things about how the python garbage collector frees up memory.

One of those is disabling garbage collection:

import gc
# once again using ctypes
import ctypes
# disabling automatic garbage collection
gc.disable()

class SomeObject():
  def __init__(self, something, something_else):
    self.something = something
    self.something_else = something_else
  def some_method(self):
    return str(self.something)

a_variable_holding_a_memory_address = SomeObject(something=94, something_else=243)
a = a_variable_holding_a_memory_address

object_id = id(a_variable_holding_a_memory_address)
print(ctypes.cast(object_id, ctypes.py_object).value)

del a_variable_holding_a_memory_address

print(ctypes.cast(object_id, ctypes.py_object).value)

del a

print(ctypes.cast(object_id, ctypes.py_object).value)

Output:

<__main__.SomeObject object at 0x7f305ae6df10>
<__main__.SomeObject object at 0x7f305ae6df10>
<_ast.Interactive object at 0x7f305ae6df10>

The object is left even though there are no references to it. Usually the automatic garbage collector would free up the memory space used to store the object, but I disabled is with gc.disable().

What is the _ast.Interactive object that is left? First here is a simple overview of how python is interpreted by the c code it is written in:

  1. Code is parsed into an array of tokens
  2. The array of tokens is used to make an abstract syntax tree (ast as in _ast).
  3. Byte code is generated from the abstract syntax tree
  4. The byte code is run

So, after all the references to an object are removed and automatic garbage collection is disabled all that is left is the code of the object one level of abstraction above byte code.

Upvotes: 1

wovano
wovano

Reputation: 5083

It's not entirely clear to me what the (purpose of) the question is, since "that doesn't seem to work." does not really describe the problem. Maybe there was some confusion about the difference between deleting an object or deleting a variable (i.e. a name).

Anyway, what is not yet mentioned in all of the current other answers, is that del is not necessary to delete an object. In fact, the user has no (direct) control over deletion of objects. This is done by the garbage collector, at some point in time, when there are no references to the object, or when the interpreter shuts down.

There are two ways of removing references to an object:

  1. Using del to remove the binding of a name from the local or global namespace:
    del barbox1
    
  2. Assigning another value to a name:
    barbox1 = None
    

In the first case, the name (the "variable") barbox1 is completely removed. Trying to access it after deleting it will result in a NameError, just like it was never assigned. In the second case, the variable still exists, but does not refer to the object anymore.

In both cases, if there are no other references to the object, the object is removed by the garbage collector (as already pointed out in most of the other answers).

NB: The __del__() method is not really relevant for deleting objects, except that it could be used to demonstrate when an object is deleted, although there are no hard guarantees when or even if the method is called. It can even be used to avoid deletion of the object. However, it certainly does not delete the object.

Upvotes: 1

MukeshRKrish
MukeshRKrish

Reputation: 1090

Python manages the memory with the concept called Reference counting

What does it mean?

When an object is created, a dedicated memory to store the object gets created and the address of the memory is returned. We basically store the address in the variable.

Python tracks the number of variables that has the object address stored, once all of the variables are removed/changed then python actually removes the memory allocated for the object.

Assume we have a class called Treasure

class Treasure:
    def __del__(self):
        print("Treasure is gone")

print("John creates a treasure and he know the location of it (count is 1)")
john = Treasure()

print("John shares the treasure location with Stark (count is 2)")
stark = john

print("Stark shares the treasure location with Chris (count is 3)")
chris = stark

print("John dies (count is 2)")
del john

print("Stark dies (count is 1)")
del stark

print("Chris dies (count is 0)")
del chris

Output

John creates a treasure and he know the location of it (count is 1)
John shares the treasure location with Stark (count is 2)
Stark shares the treasure location with Chris (count is 3)
John dies (count is 2)
Stark dies (count is 1)
Chris dies (count is 0)
Treasure is gone

Treasure is gone is printed only once after Chris dies, that is because when John died Stark & Chris knew the location and when Stark died Chris knew the location but when Chris died there is no one left who knows the location of the treasure.

the method __del__ will be called only when the last reference is deleted

You can get the current number of references to an object using getrefcount from sys Example

import sys

class A:
    """
    test class
    """

a = A()
b = a

print(sys.getrefcount(a))

Output

3

Usually the count will be one more due to the temporary reference in the getrefcount call

Upvotes: 7

stevec
stevec

Reputation: 52268

Simple answer: del <variable>

Minimal Reproducible Example

# Create variable
num = 5
num
# 5

# Delete it
del num

# Confirm it's gone
num
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# NameError: name 'num' is not defined

Upvotes: -4

gitesh.tyagi
gitesh.tyagi

Reputation: 2381

object.__del__(self) is called when the instance is about to be destroyed.

>>> class Test:
...     def __del__(self):
...         print "deleted"
... 
>>> test = Test()
>>> del test
deleted

Object is not deleted unless all of its references are removed(As quoted by ethan)

Also, From Python official doc reference:

del x doesn’t directly call x.__del__() — the former decrements the reference count for x by one, and the latter is only called when x‘s reference count reaches zero

Upvotes: 79

Ethan Furman
Ethan Furman

Reputation: 69031

What do you mean by delete? In Python, removing a reference (or a name) can be done with the del keyword, but if there are other names to the same object that object will not be deleted.

--> test = 3
--> print(test)
3
--> del test
--> print(test)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'test' is not defined

compared to:

--> test = 5
--> other is test  # check that both name refer to the exact same object
True
--> del test       # gets rid of test, but the object is still referenced by other
--> print(other)
5

Upvotes: 31

Related Questions