以适当的单位获得函数 return 值的 Pythonic 方法
Pythonic way to have a function return value in proper units
Objective: return 调用者请求的单位(或任何微不足道的修改)中的函数值。
背景:
我是 运行 Python 2.7 Raspberry Pi 3,并使用函数 distance()
来获取旋转编码器转动的距离。根据调用函数的位置,我需要不同单位的距离。那么,这应该如何以 python 方式编写(即简短且易于维护)。
第一次尝试:
我的第一次尝试是在函数中使用 米 的单位,并且有一个长的 elif
树 select 正确的单位 return英寸
def distance(units='m'):
my_distance = read_encoder()
if units == 'm':
return my_distance * 1.000
elif units == 'km':
return my_distance / 1000.
elif units == 'cm':
return my_distance * 10.00
elif units == 'yd':
return my_distance * 1.094
else:
return -1
这种方法的好处在于它可以识别不可用的单位。
第二次尝试:
我的第二次尝试是创建一个包含各种 multipliers
.
的字典
def distance(units='m'):
multiplier = {
'm': 1.000,
'km': 0.001,
'cm': 10.00
'yd': 1.094
}
try:
return read_encoder() * mulitplier[units]
except KeyError:
return -1
在这里,无法识别的单位被 KeyError
.
捕获
相关性:
我知道像 Pint 这样的现有库,但我正在寻找解决此编程问题的方法。当您在 Python 中有一个函数时,您需要以可重用的方式对输出进行轻微修改。我还有其他功能,例如 speed()
使用 'm/s' 作为基本单位,并且需要类似的 units
参数。根据我的经验,一个结构良好的程序不会在每个 return 语句之前包含一段 elif
分支。在这种情况下,如果我想更改计算单位的方式,我必须仔细 grep
通过我的代码,并确保在每个实例中更改单位的计算方式。一个合适的解决方案只需要更改一次计算。
这可能太宽泛了,但这是我 运行 坚持的模式。
字典查找很好,但不要return标记值来表示错误;只是提出一个适当的例外。它可以像让查找中的 KeyError
传播一样简单(虽然不透明)。不过,更好的解决方案是引发自定义异常:
class UnknownUnitError(ValueError):
pass
def distance(unit='m'):
multiplier = {
'm': 1.000,
'km': 0.001,
'cm': 10.00
}
try:
unit = multiplier[unit]
except KeyError:
# Include the problematic unit in the exception
raise UnknownUnitError(unit)
return read_encoder() * unit
对于您的示例,它可以是:
class DistanceUnits():
"""
Enum class for indicating measurement units and conversions between them.
Holds all related logic.
"""
M = 'm'
KM = 'km'
CM = 'cm'
def distance(units=DistanceUnits.M):
multiplier = {
DistanceUnits.M: 1.000,
DistanceUnits.KM: 0.001,
DistanceUnits.CM: 10.00
}
return read_encoder() * mulitplier[units] if units in multiplier else -1
但是,将 multipliers
移到 distance
函数之外并使其成为 DistanceUnits
的一部分是合理的。
UPD: 'how to ..' 有很多不同的方式,所有这些都取决于你的需要,但有一个主要原则 干。即使很多 elif
s 也足够好(创建字典实例在每次函数调用时消耗一些 ram..)如果你不忘记不要重复自己。
如何,使用装饰器:
def read_encoder():
return 10
multiplier = {
'm': 1.000,
'km': 0.001,
'cm': 10.00,
'yd': 1.094,
}
def multiply(fn):
def deco(units):
return multiplier.get(units, -1) * fn(units)
return deco
@multiply
def distance(units='m'):
my_distance = read_encoder()
return my_distance
print distance("m")
print distance("yd")
print distance("feet")
输出:
10.0
10.94
-10
或者,作为围绕任何无单元函数的更通用的包装器:
multiplier = {
'm': 1.000,
'km': 0.001,
'cm': 10.00,
'yd': 1.094,
}
def multiply(fn):
def deco(units, *args, **kwds):
return multiplier.get(units, -1) * fn(*args, **kwds)
return deco
@multiply
def read_encoder(var):
#I've added a variable to the function just to show that
#it can be passed through from the decorator
return 10 * var
print read_encoder("m", 1)
print read_encoder("yd", 2)
print read_encoder("feet", 3)
输出:
10.0
21.88
-30
关于引发 KeyError 与 -1 的问题是一个品味问题。就个人而言,如果找不到(如果接收者不关心),我会 return * 1 。或者抛出 KeyError。 -1 显然没有用。
最后一次迭代,使单位参数可选:
def multiply(fn):
def deco(*args, **kwds):
#pick up the unit, if given
#but don't pass it on to read_encoder
units = kwds.pop("units", "m")
return multiplier.get(units, -1) * fn(*args, **kwds)
return deco
@multiply
def read_encoder(var):
return 10 * var
print read_encoder(1, units="yd")
print read_encoder(2)
print read_encoder(3, units="feet")
10.94
20.0
-30
Objective: return 调用者请求的单位(或任何微不足道的修改)中的函数值。
背景:
我是 运行 Python 2.7 Raspberry Pi 3,并使用函数 distance()
来获取旋转编码器转动的距离。根据调用函数的位置,我需要不同单位的距离。那么,这应该如何以 python 方式编写(即简短且易于维护)。
第一次尝试:
我的第一次尝试是在函数中使用 米 的单位,并且有一个长的 elif
树 select 正确的单位 return英寸
def distance(units='m'):
my_distance = read_encoder()
if units == 'm':
return my_distance * 1.000
elif units == 'km':
return my_distance / 1000.
elif units == 'cm':
return my_distance * 10.00
elif units == 'yd':
return my_distance * 1.094
else:
return -1
这种方法的好处在于它可以识别不可用的单位。
第二次尝试:
我的第二次尝试是创建一个包含各种 multipliers
.
def distance(units='m'):
multiplier = {
'm': 1.000,
'km': 0.001,
'cm': 10.00
'yd': 1.094
}
try:
return read_encoder() * mulitplier[units]
except KeyError:
return -1
在这里,无法识别的单位被 KeyError
.
相关性:
我知道像 Pint 这样的现有库,但我正在寻找解决此编程问题的方法。当您在 Python 中有一个函数时,您需要以可重用的方式对输出进行轻微修改。我还有其他功能,例如 speed()
使用 'm/s' 作为基本单位,并且需要类似的 units
参数。根据我的经验,一个结构良好的程序不会在每个 return 语句之前包含一段 elif
分支。在这种情况下,如果我想更改计算单位的方式,我必须仔细 grep
通过我的代码,并确保在每个实例中更改单位的计算方式。一个合适的解决方案只需要更改一次计算。
这可能太宽泛了,但这是我 运行 坚持的模式。
字典查找很好,但不要return标记值来表示错误;只是提出一个适当的例外。它可以像让查找中的 KeyError
传播一样简单(虽然不透明)。不过,更好的解决方案是引发自定义异常:
class UnknownUnitError(ValueError):
pass
def distance(unit='m'):
multiplier = {
'm': 1.000,
'km': 0.001,
'cm': 10.00
}
try:
unit = multiplier[unit]
except KeyError:
# Include the problematic unit in the exception
raise UnknownUnitError(unit)
return read_encoder() * unit
对于您的示例,它可以是:
class DistanceUnits():
"""
Enum class for indicating measurement units and conversions between them.
Holds all related logic.
"""
M = 'm'
KM = 'km'
CM = 'cm'
def distance(units=DistanceUnits.M):
multiplier = {
DistanceUnits.M: 1.000,
DistanceUnits.KM: 0.001,
DistanceUnits.CM: 10.00
}
return read_encoder() * mulitplier[units] if units in multiplier else -1
但是,将 multipliers
移到 distance
函数之外并使其成为 DistanceUnits
的一部分是合理的。
UPD: 'how to ..' 有很多不同的方式,所有这些都取决于你的需要,但有一个主要原则 干。即使很多 elif
s 也足够好(创建字典实例在每次函数调用时消耗一些 ram..)如果你不忘记不要重复自己。
如何,使用装饰器:
def read_encoder():
return 10
multiplier = {
'm': 1.000,
'km': 0.001,
'cm': 10.00,
'yd': 1.094,
}
def multiply(fn):
def deco(units):
return multiplier.get(units, -1) * fn(units)
return deco
@multiply
def distance(units='m'):
my_distance = read_encoder()
return my_distance
print distance("m")
print distance("yd")
print distance("feet")
输出:
10.0
10.94
-10
或者,作为围绕任何无单元函数的更通用的包装器:
multiplier = {
'm': 1.000,
'km': 0.001,
'cm': 10.00,
'yd': 1.094,
}
def multiply(fn):
def deco(units, *args, **kwds):
return multiplier.get(units, -1) * fn(*args, **kwds)
return deco
@multiply
def read_encoder(var):
#I've added a variable to the function just to show that
#it can be passed through from the decorator
return 10 * var
print read_encoder("m", 1)
print read_encoder("yd", 2)
print read_encoder("feet", 3)
输出:
10.0
21.88
-30
关于引发 KeyError 与 -1 的问题是一个品味问题。就个人而言,如果找不到(如果接收者不关心),我会 return * 1 。或者抛出 KeyError。 -1 显然没有用。
最后一次迭代,使单位参数可选:
def multiply(fn):
def deco(*args, **kwds):
#pick up the unit, if given
#but don't pass it on to read_encoder
units = kwds.pop("units", "m")
return multiplier.get(units, -1) * fn(*args, **kwds)
return deco
@multiply
def read_encoder(var):
return 10 * var
print read_encoder(1, units="yd")
print read_encoder(2)
print read_encoder(3, units="feet")
10.94
20.0
-30