减少 if/elif 的使用
Reducing the use of if's / elif
有什么方法可以减少此代码中 if 和 elif 的数量 lists/dict/tuples?
cod =
['menu'],
['dimension 1"'],
['dimension 2”'],
['dimension 3”'],
['dimension 4'],
['dimension 5'],
['dimension 6'],
['dimension 7'],
['dimension 8'],
['dimension 9'],
['dimension 10']
]
return cod
if choice == 1:
quantify = float(input(('Quantify: ')))
if 0 < quantify <= 6:
print('± 0,1mm')
elif 6 < quantify <= 30:
print('± 0,2mm')
elif 30 < quantify <= 120:
print('± 0,3mm')
elif 120 < quantify <= 400:
print('± 0,5mm')
elif 400 < quantify <= 1000:
print('± 0,8mm')
elif 1000 < quantify <= 2000:
print('± 1,2mm')
elif 2000 < quantify <= 4000:
print('± 2mm')
else:
print('<<< Min = 0,5mm | Max = 4000mm >>>')
elif choice == 2:
quantify = float(input(('Quantify: ')))
if 0 < quantify <= 3:
print('± 0,2mm')
elif 3 < quantify <= 6:
print('± 0,5mm')
elif 6 < quantify:
print('± 1mm')
else:
print('<<< Min = 0,5mm | Max = ∞ >>>')
*我不得不更改一些东西以使其可读,因为它是葡萄牙语和其他一些功能。
谢谢,
卖卡瓦略
替换包含严格相等比较的 if...elif
链非常简单。但是,当您有一个范围时,字典并不是正确的解决方案。相反,您将需要一个自定义数据结构,将每个范围的开始和结束与 if 语句进行比较。然后您可以使用 for 循环遍历范围列表中的所有范围。
您对使用字典和列表的想法是正确的。这就是我如何简化您的代码以不使用一堆 if else 语句。
from collections import namedtuple
tolerance = namedtuple( 'tolerance', ['lower_bound', 'upper_bound', 'tolerance'] )
tolerances = {
'1': [
tolerance(0, 6, '± 0,1mm'),
tolerance(6, 30, '± 0,2mm'),
tolerance(30, 120, '± 0,3mm'),
tolerance(120, 400, '± 0,5mm'),
tolerance(400, 1000, '± 0,8mm'),
tolerance(1000, 2000, '± 1,2mm'),
tolerance(2000, 4000, '± 2mm')
],
'2': [
tolerance(0, 3, '± 0,2mm'),
tolerance(3, 6, '± 0,5mm'),
tolerance(6, 'inf', '± 1mm'),
]
}
def get_tolerance(quantify, choice):
for t in tolerances[choice]:
if t.lower_bound <= quantify <= t.upper_bound:
return t.tolerance
# if we didn't find a matching tolerance, raise an error
min_tolerance = min( t.lower_bound for t in tolerances[choice] )
max_tolerance = max( t.lower_bound for t in tolerances[choice] )
raise ValueError(f'<<< Min = {min_tolerance} | Max = {max_tolerance} >>>')
choice = input('Choice: ')
while choice not in tolerances:
print('Invalid choice. Choice must be one of the following:', ', '.join(tolerances.keys()))
choice = input('Choice: ')
quantify = float(input('Quantify: '))
print('Tolerance is:', get_tolerance(quantify, choice))
我选择使用一种叫做 named tuple 的东西来存储公差信息而不是列表。如果您从未听说过命名元组,它们的工作方式是您指定一些字段(例如 lower_bound、upper_bound、tolerance),然后在我们的例子中返回 tolerance
,您可以使用它来创建命名元组。当我们使用 tolerance
创建一个命名元组时,例如 t = tolerance(0, 6, '± 0,1mm')
然后我们可以 t.lower_bound
获得下限, t.upper_bound
获得上限, 和 t.tolerance
。当您需要存储固定数量的项目时,使用这样的命名元组而不是列表可以使代码更容易阅读。
这里有两种方法。注意到其他人也发布了类似的内容:)
""" SO QA """
import bisect
class Tolerance:
def __init__(self, lower_limit, text):
self._lower_limit = lower_limit
self._text = text
def __eq__(self, other):
return self.lower_limit == other.lower_limit
def __lt__(self, other):
return self.lower_limit < other.lower_limit
def __gt__(self, other):
return self.lower_limit > other.lower_limit
def __str__(self):
return '{:4d} {}'.format(self.lower_limit, self.text)
@property
def lower_limit(self):
return self._lower_limit
@property
def text(self):
return self._text
@staticmethod
def get(tolerance_list, value):
if isinstance(value, int):
value = Tolerance(value, "")
if isinstance(value, Tolerance):
idx = bisect.bisect_right(tolerance_list, value)
if idx:
return tolerance_list[idx-1]
raise ValueError('value {} is out of range'.format(value))
raise TypeError('unexpected type: {}'.format(type(value)))
_TOLERANCES = [
Tolerance( 0, '± 0,1mm'),
Tolerance( 6, '± 0,2mm'),
Tolerance( 30, '± 0,3mm'),
Tolerance( 120, '± 0,5mm'),
Tolerance( 400, '± 0,8mm'),
Tolerance(1000, '± 1,2mm'),
Tolerance(2000, '± 2,0mm'),
Tolerance(4000, 'over range'),
]
def get_tolerance_using_dict(value):
"""
Based on the value, get the tolerance entry.
:param value: The integer value that is within the expected range.
:returns: A entry dict {lower_limit: value, text: ""}.
"""
tolerances = [
{'lower_limit': 0, 'text': '± 0,1mm'},
{'lower_limit': 6, 'text': '± 0,2mm'},
{'lower_limit': 30, 'text': '± 0,3mm'},
{'lower_limit': 120, 'text': '± 0,5mm'},
{'lower_limit': 400, 'text': '± 0,8mm'},
{'lower_limit': 1000, 'text': '± 1,2mm'},
{'lower_limit': 2000, 'text': '± 2,0mm'},
{'lower_limit': 4000, 'text': 'over range'},
]
prev_entry = None
for entry in tolerances:
if entry['lower_limit'] <= value:
prev_entry = entry
else:
return prev_entry
return tolerances[len(tolerances) - 1]
# Perhaps a better way to handle the range error:
# raise ValueError('value is out of range'.format(value))
def main():
""" Test the stuff """
values = [0, 1, 2, 3, 4, 5, 6, 7, 8, 29, 30, 100, 119, 120, 121,
1999, 2000, 2001, 3999, 4000, 4001]
print('using class:')
for value in values:
print('{:3} : {}'.format(value, Tolerance.get(_TOLERANCES, value)))
print('using dict:')
for value in values:
print('{:3} : {}'.format(value, get_tolerance_using_dict(value)))
if __name__ == "__main__":
main()
有什么方法可以减少此代码中 if 和 elif 的数量 lists/dict/tuples?
cod =
['menu'],
['dimension 1"'],
['dimension 2”'],
['dimension 3”'],
['dimension 4'],
['dimension 5'],
['dimension 6'],
['dimension 7'],
['dimension 8'],
['dimension 9'],
['dimension 10']
]
return cod
if choice == 1:
quantify = float(input(('Quantify: ')))
if 0 < quantify <= 6:
print('± 0,1mm')
elif 6 < quantify <= 30:
print('± 0,2mm')
elif 30 < quantify <= 120:
print('± 0,3mm')
elif 120 < quantify <= 400:
print('± 0,5mm')
elif 400 < quantify <= 1000:
print('± 0,8mm')
elif 1000 < quantify <= 2000:
print('± 1,2mm')
elif 2000 < quantify <= 4000:
print('± 2mm')
else:
print('<<< Min = 0,5mm | Max = 4000mm >>>')
elif choice == 2:
quantify = float(input(('Quantify: ')))
if 0 < quantify <= 3:
print('± 0,2mm')
elif 3 < quantify <= 6:
print('± 0,5mm')
elif 6 < quantify:
print('± 1mm')
else:
print('<<< Min = 0,5mm | Max = ∞ >>>')
*我不得不更改一些东西以使其可读,因为它是葡萄牙语和其他一些功能。
谢谢, 卖卡瓦略
替换包含严格相等比较的 if...elif
链非常简单。但是,当您有一个范围时,字典并不是正确的解决方案。相反,您将需要一个自定义数据结构,将每个范围的开始和结束与 if 语句进行比较。然后您可以使用 for 循环遍历范围列表中的所有范围。
您对使用字典和列表的想法是正确的。这就是我如何简化您的代码以不使用一堆 if else 语句。
from collections import namedtuple
tolerance = namedtuple( 'tolerance', ['lower_bound', 'upper_bound', 'tolerance'] )
tolerances = {
'1': [
tolerance(0, 6, '± 0,1mm'),
tolerance(6, 30, '± 0,2mm'),
tolerance(30, 120, '± 0,3mm'),
tolerance(120, 400, '± 0,5mm'),
tolerance(400, 1000, '± 0,8mm'),
tolerance(1000, 2000, '± 1,2mm'),
tolerance(2000, 4000, '± 2mm')
],
'2': [
tolerance(0, 3, '± 0,2mm'),
tolerance(3, 6, '± 0,5mm'),
tolerance(6, 'inf', '± 1mm'),
]
}
def get_tolerance(quantify, choice):
for t in tolerances[choice]:
if t.lower_bound <= quantify <= t.upper_bound:
return t.tolerance
# if we didn't find a matching tolerance, raise an error
min_tolerance = min( t.lower_bound for t in tolerances[choice] )
max_tolerance = max( t.lower_bound for t in tolerances[choice] )
raise ValueError(f'<<< Min = {min_tolerance} | Max = {max_tolerance} >>>')
choice = input('Choice: ')
while choice not in tolerances:
print('Invalid choice. Choice must be one of the following:', ', '.join(tolerances.keys()))
choice = input('Choice: ')
quantify = float(input('Quantify: '))
print('Tolerance is:', get_tolerance(quantify, choice))
我选择使用一种叫做 named tuple 的东西来存储公差信息而不是列表。如果您从未听说过命名元组,它们的工作方式是您指定一些字段(例如 lower_bound、upper_bound、tolerance),然后在我们的例子中返回 tolerance
,您可以使用它来创建命名元组。当我们使用 tolerance
创建一个命名元组时,例如 t = tolerance(0, 6, '± 0,1mm')
然后我们可以 t.lower_bound
获得下限, t.upper_bound
获得上限, 和 t.tolerance
。当您需要存储固定数量的项目时,使用这样的命名元组而不是列表可以使代码更容易阅读。
这里有两种方法。注意到其他人也发布了类似的内容:)
""" SO QA """
import bisect
class Tolerance:
def __init__(self, lower_limit, text):
self._lower_limit = lower_limit
self._text = text
def __eq__(self, other):
return self.lower_limit == other.lower_limit
def __lt__(self, other):
return self.lower_limit < other.lower_limit
def __gt__(self, other):
return self.lower_limit > other.lower_limit
def __str__(self):
return '{:4d} {}'.format(self.lower_limit, self.text)
@property
def lower_limit(self):
return self._lower_limit
@property
def text(self):
return self._text
@staticmethod
def get(tolerance_list, value):
if isinstance(value, int):
value = Tolerance(value, "")
if isinstance(value, Tolerance):
idx = bisect.bisect_right(tolerance_list, value)
if idx:
return tolerance_list[idx-1]
raise ValueError('value {} is out of range'.format(value))
raise TypeError('unexpected type: {}'.format(type(value)))
_TOLERANCES = [
Tolerance( 0, '± 0,1mm'),
Tolerance( 6, '± 0,2mm'),
Tolerance( 30, '± 0,3mm'),
Tolerance( 120, '± 0,5mm'),
Tolerance( 400, '± 0,8mm'),
Tolerance(1000, '± 1,2mm'),
Tolerance(2000, '± 2,0mm'),
Tolerance(4000, 'over range'),
]
def get_tolerance_using_dict(value):
"""
Based on the value, get the tolerance entry.
:param value: The integer value that is within the expected range.
:returns: A entry dict {lower_limit: value, text: ""}.
"""
tolerances = [
{'lower_limit': 0, 'text': '± 0,1mm'},
{'lower_limit': 6, 'text': '± 0,2mm'},
{'lower_limit': 30, 'text': '± 0,3mm'},
{'lower_limit': 120, 'text': '± 0,5mm'},
{'lower_limit': 400, 'text': '± 0,8mm'},
{'lower_limit': 1000, 'text': '± 1,2mm'},
{'lower_limit': 2000, 'text': '± 2,0mm'},
{'lower_limit': 4000, 'text': 'over range'},
]
prev_entry = None
for entry in tolerances:
if entry['lower_limit'] <= value:
prev_entry = entry
else:
return prev_entry
return tolerances[len(tolerances) - 1]
# Perhaps a better way to handle the range error:
# raise ValueError('value is out of range'.format(value))
def main():
""" Test the stuff """
values = [0, 1, 2, 3, 4, 5, 6, 7, 8, 29, 30, 100, 119, 120, 121,
1999, 2000, 2001, 3999, 4000, 4001]
print('using class:')
for value in values:
print('{:3} : {}'.format(value, Tolerance.get(_TOLERANCES, value)))
print('using dict:')
for value in values:
print('{:3} : {}'.format(value, get_tolerance_using_dict(value)))
if __name__ == "__main__":
main()