Python simply reports the number it gets from the OS. The OS simply reports the number it gets from the firmware. The firmware simply reports the number it gets from the CPU.
So, the short answer to your question is: Python is reporting 20 CPUs because that is what Intel has decided to report.
Now, the question is of course: does it make sense to report 20 CPUs? And the answer to that is not simple. At the time when the system calls that report the number of CPUs were designed, the relationship between sockets, chips, dies, CPUs, execution cores, and threads was a very simple 1:1:1:1:1:1 relationship. So, nobody ever thought about whether the number should mean the number of sockets, the number of CPUs, the number of cores, the number of threads, or whatever, because it didn't matter. It was all the same.
But nowadays, the relationship is much more complex:
- a socket can hold a package that contains multiple chips
- each chip can contain multiple dies
- each die can contain multiple CPUs
- each CPU can have multiple execution cores
- each core can potentially execute multiple threads (mostly) in parallel
So, you have to think about what it actually is that you are interested in. And Intel has decided that what you are most likely interested in, is the number of hardware threads that can be executed in parallel. And since on the particular CPU that you have, there are 10 execution cores in the CPU and each core can execute 2 threads, the CPU reports itself as 20 CPUs, even though it is only 1 CPU.
Because as a programmer, you most likely don't care how many blobs of sand you have in your computer, but what you can do with them.
Although in reality, the question is even more complex because the two threads per execution core are not totally independent, and depending on your specific workload, you might actually only want to use one thread per CPU, so you might actually need to know the difference between execution cores and threads. Additionally, some recent CPUs have different types of cores, e.g. the Apple M1 CPU has 8 cores with identical Instruction Sets, but 4 of them are optimized for resources (and thus somewhat slower) and 4 of them are optimized for performance (and thus consume more power and produce more waste heat).
The current SPARC CPUs from Oracle can schedule up to 8 threads per execution core, of which they can execute up to 2 simultaneously. So, should this CPU report itself as 2 CPUs or 8? And so on, there are dozens of such examples that show that the answer to the question "how many CPUs do I have" is not so simple, and depends heavily on what, precisely, you actually mean by "CPU".
If you want to write high-performance and/or energy-efficient code, a simple number is not enough. You need to know the full hierarchy and dependencies between the different elements.