In addition to what others have said about just passing two parameters, there also row types, where the signature of `calculate_price` can be specified to accept any record that has the two required fields.
I don't write Python, but I think row level typing is stricter. Both the names and types of the record fields would have to satisfy the function signature, so the quacking is only honored on field names. Where dynamic languages will of course accept floats where ints are called for, etc, quacking all the way down.
The point of my original comment was to suggest that some of the flexibility offered by duck typing can be achieved in FP, so they should seem similar.
I would still just pass the fields as two parameters.