What is the lifetime of a class instance and a "module instance"?

Asked

Viewed 49 times

2

An object instance exists until its father is destroyed, i.e.:

class AnyClass:

    def __init__(self):
        self.any_date = datetime.date.today()

(any_date)It will exist until the moment that its "parent object" (instance of AnyClass) be picked up and destroyed by the garbage collector.

And what would be the lifetime of class objects and "module objects"?

Class object:

class AnyClass:
    any_time = datetime.datetime.now()

What is the lifetime of any_time?

Module object:

#file test.py

ANY_DATE = datetime.date.today()

class AnyClass:

    def __init__(self):
        self.any_date = datetime.date.today()

What is the lifetime of ANY_DATE?

1 answer

6


TL;DR: Classes and modules exist throughout the life of the process, from the moment the module is first imported (in the case of classes, the existing classes within the modules). The attributes of these classes and modules also track the life of their "parents". They only cease to exist if they are explicitly deleted by the command del.

full answer

One of the cool things in Python is that the language works with a small set of rules and there are very few exceptions or special cases.

So you may have heard that "everything in Python is an object". "everything" is "everything" - including classes and modules.

And by default, objects in Python have, internally, a reference count: that’s - every reference, whether it’s a variable name, or as content of a data structure like a list, dictionary or set there’s an object increases that reference count by "1". When the last reference to an object is destroyed and the object’s reference count reaches zero, its method __del__ is called and then, the object is discarded and its memory is released (this destruction does not depend on code in the method __del__ - it is made by the language Runtime - even if the __del__ do not call the corresponding method in super-classes).

So just get the terminology right and it’s easy to answer your question: What you are calling "object instance" are actually "instance attributes" (attributes created with self. ... within object methods). What you call "class objects" - name assignments made in the body of a command class - are "class attributes". What you call "module object" can have this name, or we can simply call "variables at module level" or "global variables" (they are called "global", but in fact they are always at module level).

And, each of the objects you are in doubt, as well as all the other objects in Python, exists to the point where no other reference to it exists. In the case of instance attributes, if the instance to which they belong is destroyed, the attributes are destroyed together (unless there is some external variable pointing to the same object):

>>> class TesteApaga:
...    count = 0
...    def __init__(self):
...         self.count = self.__class__.count
...         self.__class__.count += 1
...    def __del__(self):
...         print(f"Instância {self.count} apagada!")
... 
>>> a = TesteApaga()
>>> del a
Instância 0 apagada!
>>> class B:
...   def __init__(self):
...      self.a = TesteApaga()
... 
>>> b = B()
>>> del b
Instância 1 apagada!

But not:

>>> b = B()
Instância 6 apagada!
>>> c = b.a
>>> del b
>>> # há uma referência ainda dentro da variável 'c'
... 
>>> del c
Instância 2 apagada!

For class attributes, the same is true - when the class itself in which the attribute is declared is deleted, its attributes are deleted.

What happens there is that the classes themselves are noted in some internal records - at least in object.__subclasses__, for example, so not always when we give the command del to delete a class, the reference count of the class itself comes to zero - in this case, yes, the "Garbage collector" comes into action - at some point, after a del in the class itself it will "realize" that the class no longer has references and delete the class itself internally. At that point, your attributes are also destroyed.

In interactive mode, when declaring:

>>> class C:
...   c = TesteApaga()
... 
>>> del C

No "instance 2 deleted" printed immediately - just a few lines later when I went to use the shell "autocomplete" feature.

Of course instead of depending on the class being deleted, if you want to free resources that are in the object in question, you can always use the del explicitly:

>>> class D:
...   d = TesteApaga()
... 
>>> d = D()
>>> 
>>> del D.d
Instância 3 apagada!

In this case, unlike when we directly erase the D, no need to wait for the collector Garbage.

For modules the same thing - A variable (or function statement, or class declaration, or imported name) in a module gets a reference in the internal dictionary of that module (the attribute .__dict__ of the module itself).

Just delete the module attribute directly and that reference no longer exists.

Now, what will never be enough is to delete the module only from the local namespace - when a module is imported in Python, in addition to the names in the place where the import, there is a reference to the module which is in sys.modules - which is a dictionary where the keys are the module names, and the values are the "module" objects themselves. When deleting a module either from the local namespace or from sys.modules, yes, if the module has not been imported at any other point in the same process, its references reach 0, and its attributes are destroyed.

In this example, I create an empty ". py" file, which is imported as a module, create an object inside - see how it is deleted only when I delete it from sys modules.:

>>> open("modulo_teste.py", "wt")
<_io.TextIOWrapper name='modulo_teste.py' mode='wt' encoding='UTF-8'>
>>> import modulo_teste
>>> modulo_teste.e = TesteApaga()
>>> 
>>> del modulo_teste
>>> del sys.modules["modulo_teste"]
Instância 4 apagada!
>>> 

Or, of course, if the del directly in the variable that points to it:

>>> import modulo_teste
>>> modulo_teste.f = TesteApaga()
>>> 
>>> del modulo_teste.f
Instância 5 apagada!
>>> 

Returning to your question about "life time": in a "normal" Python script, modules and classes declared as code within the modules are typically never deleted - these objects exist since the module is imported and executed, and persist until the end of the program.

Only explicit removal of these objects with the command del causes them to be destroyed first.

And finally, of course if the program makes use of multi-processing techniques in external processes like "subprocess", "Concurrent.Futures" or "Celery",which create work processes (worker processes), when these processes-child are terminated the respective objects are also destroyed - add this information if any of the attributes points to an open file, or port socket - operating system resources that can only be used for one process at a time.

In Python web backend applications, in production, typically the number of processes/threads of an application is not under the control of the developer - the WSGI server controls this. In those, in each process classes and modules are created independently. (for example, if your app is being served in 5 processes with 4 threads in each, Python will execute the code that creates your class 5 times - and they will be visible in all 20 threads that exist in total).

  • Hello John! Sorry to resume the question after marking it as answered, is that a new question arose. In this case class instances begin to exist from the moment the program executes and are destroyed from the moment the class is also destroyed. If the class is not destroyed manually, i.e., by means of the command del it will exist from the beginning to the end of the application, as well as its respective instances, that is, with a behavior equal to global variables, where they exist as long as the module exists that can be "always". Is that it? memory Leak?

  • 1

    This - a class or module is created, and exists forever - and the attributes declared in the class exist while the program is running unless the class statement itself is explicitly deleted by a del. (and, in the case of modules, the del must also be in sys.modules["modulo"]) (again insist on terminology: "class attribute" not "instance" - "class instance" is the term for an object created with that class, which normally has a shorter life)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.