When you come across some Python code for something written 5 years ago and they used four contributed packages that the programmers have changed the API on three times since then, you want to set up a virtual environment that contains those specific versions so you can at least see how it worked at that time. A small part of this headache comes from Python itself mutating, but the bulk of the problem is the imported user-contributed packages that multiply the functionality of Python.
To be sure, it would be nice if those programmers were all dedicated to updating their code, but with hundreds of thousands of packages that could be imported written by volunteers, you can’t afford to expect all of them them to stop innovating or even to continue maintaining past projects for your benefit.
If you have the itch to fix something old so it works in the latest versions of everything, you have that option… but it is really hard to do that if you cannot see it working as it was designed to work when it was built.
Read other people’s code… particularly code by experienced developers. One good way to do that is to single-step debugging through the test code in a well-known package, stepping into the code being tested.
I suppose if you don’t know how test frameworks like pytest work, tackling how they work and how to do single-stepping with some toy example code will be a prerequisite for the above, as will spending some time studying how packages are made. (The latter may seem unattractively tedious, but the knowledge will pay off even if you never become an expert at making your own packages.)
These exercises are very likely to expose weaknesses in your understanding of all sorts of things. Be patient and keep studying!