[Python-ideas] Units in type hints
Chris Angelico
rosuav at gmail.com
Fri May 15 17:28:36 CEST 2015
On Sat, May 16, 2015 at 12:00 AM, Koos Zevenhoven
<koos.zevenhoven at aalto.fi> wrote:
> On 14.5.2015 14:59, Steven D'Aprano wrote:
>> But that's not an error. Calling sleep(weight_in_kilograms) is an error.
>
> In the example I gave, it is clearly an error. And it would be an error with
> time.sleep. But you are obviously right, sleeping for kilograms is also an
> error, although a very bizarre one.
I dunno, maybe you're a heavy sleeper? :)
>> If the user has to do the conversion themselves,
>> that's a source of error:
>>
>> sleep(time_in_milliseconds / 1000) # convert to seconds
>>
>> If you think that's too obvious an error for anyone to make,
>
> You lost me now. There does not seem to be an error in the line of code you
> provided, especially not when using Python 3, which has true division by
> default. However, in what I proposed, the type checker would complain
> because you made a manual conversion without changing the unit hint (which
> is also potential source of error, and you seem to agree).
Dividing a unit-aware value by a scalar shouldn't be an error. "I have
an A4 sheet of paper. If I fold it in half seven times, how big will
it be?" => 210mm*297mm/(2**7) == 487.265625 mm^2.
The unit would simply stay the same after the division; what you'd
have is the thousandth part of the time, still in milliseconds. If you
have a typing system that's unit-aware, this would still be an error,
but it would be an error because you're still giving milliseconds to a
function that wants seconds.
It'd possibly be best to have actual real types for your unit-aware
values. Something like:
class UnitAware:
def __init__(self, value: float, unit: str):
self.value = value
self.unit = unit
def __mul__(self, other):
if isinstance(other, UnitAware):
# perform compatibility/conversion checks
else: return UnitAware(self.value * other, self.unit)
# etc
def as(self, unit):
# attempt to convert this value into the other unit
Then you could have hinting types that stipulate specific units:
class Unit(str):
def __instancecheck__(self, val):
return isinstance(val, UnitAware) and val.unit == self
ms = Unit("ms")
sec = Unit("sec")
m = Unit("m")
This would allow you to go a lot further than just type hints. But
maybe this would defeat the purpose, in that it'd have to have every
caller and callee aware that they're looking for a unit-aware value
rather than a raw number - so it wouldn't be easy to deploy
backward-compatibly.
ChrisA
More information about the Python-ideas
mailing list