变量命名的Python约定以指示单位

Rob*_*ugg 8 python pep8 naming-conventions

首先,当我询问单位时,我的意思是测量单位,如英寸,英尺,像素,单元格.我不是指像int和float这样的数据类型.

维基百科将此称为逻辑数据类型而非物理数据类型.

我想知道命名变量的最佳方法.

这里有一些代码可以解决我的问题:

board_length=8 #in inches
board_length=8*12 #Convert from feet to inches
Run Code Online (Sandbox Code Playgroud)

请注意,这些都是整数(或浮点数,我不在乎),但我已经更改了单位.我还保持变量名称相同.我可以建立一个公约,这就是这个问题的目的.没有指导,我可能会这样做:

board_length=8
board_length_inches=8*12
Run Code Online (Sandbox Code Playgroud)

我认为这是一种特殊的做事方式.或者,我可以建立一个约定:

Fboard_length=8
Iboard_length=8*12
Run Code Online (Sandbox Code Playgroud)

或者我同样不喜欢的其他变体.我如何以描述性方式命名变量,但尽可能接近PEP-08

为了尽可能清楚,变量可能有不同的数据类型,但单位将是相同的(英寸将具有相同的命名,无论它是否存储为整数或浮点数)

Sil*_*Ray 9

虽然您可以提出一个命名约定,但通过构建一个表示"距离"的对象可以更好地服务,该对象具有以不同单位读/写的属性.例如:

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
Run Code Online (Sandbox Code Playgroud)

您甚至可以使它更通用,以便您可以轻松扩展新的转换.(注:编辑此内容根据评论进行记忆)

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)
Run Code Online (Sandbox Code Playgroud)


Bri*_*new 2

我会更进一步,使用单独的对象类型来提供类型安全,而不是简单地依赖命名约定。否则,您可以将代表英寸的变量传递到需要英里的方法中。

我认为依赖命名约定将难以长期维护,而使用类型将为您提供更大的灵活性和安全性(例如,提供内置于对象类型中的转换等)