首先,当我询问单位时,我的意思是测量单位,如英寸,英尺,像素,单元格。我不是指像int和float这样的数据类型。
Wikipedia将此称为逻辑数据类型,而不是物理数据类型。
我想知道命名变量的最佳方法。
这里有一些代码可以解决我的问题:
board_length=8 #in inches
board_length=8*12 #Convert from feet to inches
请注意,这些都是整数(或浮点数,我不在乎),但我已经更改了单位。我还保持变量名称相同。我可以建立一个公约,这就是这个问题的目的。如果没有指导,我可能会这样做:
board_length=8
board_length_inches=8*12
我认为这是一种特殊的做事方式。或者,我可以建立一个约定:
Fboard_length=8
Iboard_length=8*12
或者我同样不喜欢的其他变体。我如何以描述性方式命名变量,但尽可能接近PEP-08?
为了尽可能清楚,变量可能有不同的数据类型,但单位将是相同的(英寸将具有相同的命名,无论它是否存储为整数或浮点数)
答案 0 :(得分: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
您甚至可以使其更通用,以便您可以轻松扩展新的转化。 (注:编辑此内容根据评论进行记忆)
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)
答案 1 :(得分:2)
如果您想获得更强大的单位支持,请查看PyPi's Pint module。它并没有直接处理你的命名约定问题,但它可能需要花费很多工作来处理频繁的转换。您可以在此处找到有关它和其他一些单元模块的信息:
http://www.drdobbs.com/jvm/quantities-and-units-in-python/240161101
答案 2 :(得分:1)
我会更进一步,有单独的对象类型提供类型安全,而不是简单地依赖命名约定。否则,您可以将表示英寸的变量传递给需要英里数的方法。
我认为依赖命名约定对于长期维护会有问题,并且使用类型将为您提供更多的灵活性和安全性(例如,提供内置于对象类型中的转换等)
答案 3 :(得分:0)
...六年后...
问了很长时间,我偶然发现了python类型库。它提供了一种(运行时)免费的静态类型方法来检查变量,而不仅仅是“ int”或“ float”,而是“ inches”和“ meters”:
from typing import NewType
UserId = NewType('UserId', int)
some_id = UserId(524313)
这使我获得了大部分的收获。