Domanda

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)

È stato utile?

Soluzione 2

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)

Altri suggerimenti

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)

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top