Being "private" (as opposed to "public") is not a literal configuration attribute of a subnet.
It's derived from the subnet's associated route table... although it's not a literal configuration attribute of the route table, either.
If a subnet's traffic is routed to an Internet gateway, the subnet is known as a public subnet.
This means directly to the Internet Gateway, not via a NAT Gateway, NAT Instance, Virtual Private Gateway, or other gateway-type device.
As typically deployed, a public subnet is a subnet whose associated route table has a default route that points to the Internet Gateway object... though it could also be a subnet with a route table that had only specific destinations routing directly to the Internet Gateway, and that would still essentially be a public subnet.
Because the configuration does have some flexibility, there's not a strict delineation. For practical purposes, any subnets that are associated with route tables with routes pointing to the Internet Gateway could typically be assumed to be "public" subnets, and the rest would be "private," so the discovery process would amount to traversing the hierarchy starting from the other direction, from the VPC → Route Tables (those with IGW routes = public) → associated Subnets for those route tables.