I think you missed the issue at hand:
> even if you keep all your fields private, the constructor is still, inherently, public.
ShippingOptions and the literals / enums are part of the public API, so the user would just be writing
ShippingOptions(Carrier.USPS, Conveyance.Air)
with no hint that they're doing anything wrong.Dataclasses do have a `kw_only` option, but I'm not sure how well underscore prefixes would be understood as private parameters / a private ctor, whereas wrapping a clearly "private" type should be clear to everybody.
Glyph is not entirely correct on the "any class" bit as you can always break the default init path:
class ShippingOptions:
_ship: Literal["fast", "normal", "slow"]
__init__ = None
def shipFast() -> ShippingOptions:
opts = object.__new__(ShippingOptions)
opts._ship = "fast"
return opts
however that's a pretty ugly pattern, and unlike the one they propose I doubt tooling would understand it.