What is the reason of adding this underscore? What problem is being solved?
Imports.
import functools as _functools
import warnings as _warnings
import io as _io
import os as _os
import shutil as _shutil
import errno as _errno
from random import Random as _Random
import sys as _sys
import types as _types
import weakref as _weakref
import _thread
_allocate_lock = _thread.allocate_lock
Originally, it was because of the star import. You do not want from some_module import * adding unrelated names in your namespase. Now you can use __all__ to specify explicitly the list of names for the star import, but it is often easier to just add underscores for all non-public names. Additionally, they will not be shown in the tab-completion suggestions. It may also be a matter of style.
Sometimes, in the past, people imported some stdlib modules from other stdlib modules by mistakes, like: from os import re instead of import re (I don’t recall exactly which module was exposing .re). This code broken when re was no longer imported (to speed up Python startup).