Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python convention for variable naming to indicate units

First, when I ask about units I mean units of measurement like inches, feet, pixels, cells. I am not referring to data types like int and float.

Wikipedia refers to this as logical data type rather than physical data type.

I'd like to know the best way to name variables.

Here is some code to walk through what I'm asking:

board_length=8 #in inches
board_length=8*12 #Convert from feet to inches

Notice that these are both integers (or floats, I don't care), yet I’ve changed units. I’ve also kept the variable name the same. I could establish a convention, and that’s the purpose of this question. Without guidance, I might do something like this:

board_length=8
board_length_inches=8*12

I would consider this an ad-hoc way of doing things. Or, I might establish a convention:

Fboard_length=8
Iboard_length=8*12

Or other variants that I equally dislike. How might I name variables in a descriptive way, yet stay as close to PEP-08 as possible?

Just to be as clear as I can, the variables may have different data types, yet the units would be the same (inches would have the same naming regardless of if it was stored as and integer or a float)

like image 536
Robert Lugg Avatar asked Feb 11 '14 17:02

Robert Lugg


People also ask

What are the naming conventions for variable names in Python?

Python naming conventions for variable names are same as function names. There are some rules we need to follow while giving a name for a Python variable. Rule-1: You should start variable name with an alphabet or underscore (_) character. Rule-2: A variable name can only contain A-Z,a-z,0-9 and underscore (_).

How to name private variables in Python?

Python does not support privacy directly. This naming convention is used as a weak internal use indicator. Should follow the above naming conventions. Should use a leading underscore (_) to distinguish between "public" and "private" variables. For more read the official python documentation.

How do you name a global variable in Python?

There are certain rules we need to follow while naming a global variable. Rule-1: You should use all lowercase while deciding a name for a Object. Rule-2: If there are multiple words in your global variable name then they should be separated by an underscore (_). What is Snake_case naming style Python?

What are the rules for naming a class in Python?

Not begin with the special characters like e.g. & (ampersand), $ (dollar) If the name contains multiple words, it should be separated by underscores (_) e.g. json_string Avoid one-character variables e.g. a, b class Student age = None ... Python does not support privacy directly. This naming convention is used as a weak internal use indicator.


2 Answers

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)
like image 54
Silas Ray Avatar answered Sep 24 '22 09:09

Silas Ray


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)

like image 27
Brian Agnew Avatar answered Sep 24 '22 09:09

Brian Agnew