Python convention for variable naming to indicate units
I'd go further and have separate object types providing type safety rather than simply rely on naming conventions. Otherwise you could pass a variable representing inches into a method requiring miles.
I think that relying on naming conventions is going to be problematic to maintain long term and making use of types will give you much more flexibility and safety (e.g. providing conversions etc. built into the object types)
If you want more robust unit support, you should check out PyPi's Pint module. It doesn't directly deal with your question of naming convention, but it can take a lot of the work out of dealing with frequent conversions. You can find info on it and some other unit modules here:
http://www.drdobbs.com/jvm/quantities-and-units-in-python/240161101
...six years later...
Long after my question, I stumbled on the python typing library. It provides a (runtime) free method of static type checking a variable more specifically than just "int" or "float" but instead "inches" and "meters":
from typing import NewType
UserId = NewType('UserId', int)
some_id = UserId(524313)
This gets me most of what I was after.
While you could come up with a naming convention, you might be better served by building an object representing "distance" with properties to read/write in different units. For instance:
class Distance(object):
def __init__(self):
self._inches = 0
@property
def inches(self):
return self._inches
@inches.setter
def inches(self, value):
self._inches = value
@property
def feet(self):
return self._inches/12
@feet.setter
def feet(self, value):
self._inches = value * 12
You could even make it more generic, so that you could easily extend with new conversions. (Note: Edited this to memoize based upon comments)
from collections import defaultdict
class Distance(object):
_conversion_map = defaultdict(lambda: {'to' : None, 'from' : None})
def __init__(self, **kwargs):
self._memo = {}
if kwargs:
unit, value = kwargs.iteritems().next()
if unit == 'inches':
self.inches = value
else:
setattr(self, unit, value)
else:
self.inches = 0
def __getattr__(self, name):
if name in self._conversion_map:
try:
return self._memo[name]
except KeyError:
converter = self._conversion_map[name]['to']
if converter is None:
raise AttributeError
converted = converter(self.inches)
self._memo[name] = converted
return converted
else:
raise AttributeError
def __setattr__(self, name, value):
if name == '_memo':
super(Distance, self).__setattr__(name, value)
else:
# Clear memoized values if setting the value of the object
self._memo = {}
if name == 'inches':
super(Distance, self).__setattr__(name, value)
if name in self._conversion_map:
converter = self._conversion_map[name]['from']
if converter is None:
raise AttributeError
self._memo[name] = value
self.inches = converter(value)
else:
raise AttributeError
@classmethod
def converter(cls, func):
direction, unit = func.__name__.split('_', 1)
cls._conversion_map[unit][direction] = func
return func
@Distance.converter
def to_feet(value):
return value / 12
@Distance.converter
def from_feet(value):
return value * 12
board_1_length = Distance(feet=2)
board_2_length = Distance(inches=14)
board_1_length.inches # 24
board_2_length.feet # 1 (integer division)