A new bitcoin user "U" first generates a private key. He can compute several public keys from this private key.
The kind of private key you are referring to is an extended private key which is described in the Bitcoin Improvement Proposal 0032 (BIP32) or, like RedGrittyBrick explained, what powers HD wallets.
An extended private key contains only ...
A modern Bitcoin wallet program can generate many private-keys, each private-key has a public-key. For the most common transaction types, a Bitcoin-address is derived from the public-key.
As you say it is normal to generate a new address (i.e. a new set of keys) for each transaction. This is because all the transaction data is public knowledge - it is in the ...
I am using a different bitcoin library. This prints address and hash160 from a private key:
from bitcoinutils.setup import setup
from bitcoinutils.keys import P2pkhAddress, PrivateKey, PublicKey
# setup the network
# provide a private WIF key
priv = PrivateKey.from_wif('...
There is no math that would get the private key from a public key. That is the whole point of the Elliptic-Curve Cryptography. You can always get the public key from a private key, but not the opposite since this would mean that anybody could spend the Bitcoins of anybody and Bitcoin itself would be worthless.