Without DI, there's too much flexibility in how objects get constructed. If you want to add new functionality to a legacy code base, it can be difficult to track down the different integration points and slow to plumb through your dependencies. These projects can turn into spaghetti very quickly.
DI solves this with a simple recipe: define your functionality, define your dependencies, wire it up to the injector.
The pattern is useful in all OO languages, Python and C++ included.
you can chose to not use DI frameworks at all..