Python Switch/Case 语句改编
Python Switch/Case Statement Adaptation
好吧,冒着因不 'trying harder' 而被嘲笑的风险,我有一个场景,我一直在尝试适应 pythonic switch case 语句。我知道 python 在 3.10 中有新的 match
方法,但在我的 AWS 用例中我仅限于 3.8.10。我一直在阅读其他语言的 switch case,我想找到一种 pythonic 方法将以下混乱的 if/elif/else
语句转换为干净的 switch case。我想知道在这种情况下其他人会怎么做
OBJECTIVE:我有一个文件名将传递到此代码序列中,我需要 return 前三项(即 transaction_recipient_verification
、transaction_account_tokenization
, ETC)。有时代码会收到一个包含“field_results”或“发行者”的文件名,我需要确保修剪后的 return 字符串包含相应的大小写。
import random
sampleKeys = [
'transaction_recipient_notification_status_sent/transaction_recipient_notification_status_sent_2021_10_29_12_02_14.snappy',
'transaction_recipient_payment_status_success/transaction_recipient_payment_status_success_2021_10_29_12_02_14.snappy',
'transaction_recipient_verification_rvdm_failure/transaction_recipient_verification_rvdm_failure_2021_10_29_12_02_14.snappy',
'transaction_recipient_verification_rvdm_failure_field_results/transaction_recipient_verification_rvdm_failure_2021_10_29_12_02_14.snappy',
'transaction_recipient_authentication_status_success/transaction_recipient_authentication_status_success_2021_10_29_12_02_14.snappy',
'transaction_recipient_authentication_status_success_field_results/transaction_recipient_authentication_status_success_2021_10_29_12_02_14.snappy',
'transaction_account_tokenization_success/transaction_account_tokenization_success_2021_10_29_12_02_14.snappy',
'transaction_account_tokenization_success_issuers/transaction_account_tokenization_success_2021_10_29_12_02_14.snappy',
'transaction_recipient_payment_status_terminated/transaction_recipient_payment_status_terminated_2021_10_29_12_02_14.snappy',
'transaction_recipient_verification_rvdm_success/transaction_recipient_verification_rvdm_success_2021_10_29_12_02_14.snappy',
'transaction_recipient_verification_rvdm_success_field_results/transaction_recipient_verification_rvdm_success_2021_10_29_12_02_14.snappy',
'transaction_recipient_notification_status_received/transaction_recipient_notification_status_received_2021_10_29_12_02_14.snappy',
'transaction_recipient_authentication_status_success/transaction_recipient_authentication_status_success_2021_10_29_11_17_45.snappy'
]
key = random.choice(sampleKeys)
array_data = any(substring in key for substring in ['_issuers', '_field_results'])
if not array_data:
if 'transaction_recipient_notification' in key:
keySubject = 'transaction_recipient_notification'
elif 'transaction_recipient_authentication' in key:
keySubject = 'transaction_recipient_authentication'
elif 'transaction_recipient_verification' in key:
keySubject = 'transaction_recipient_verification'
elif 'transaction_account_verification' in key:
keySubject = 'transaction_account_verification'
elif 'transaction_account_tokenization' in key:
keySubject = 'transaction_account_tokenization'
elif 'transaction_recipient_payment' in key:
keySubject = 'transaction_recipient_payment'
else:
if '_issuers' in key:
if 'transaction_recipient_notification' in key:
keySubject = 'transaction_recipient_notification_issuers'
elif 'transaction_recipient_authentication' in key:
keySubject = 'transaction_recipient_authentication_issuers'
elif 'transaction_recipient_verification' in key:
keySubject = 'transaction_recipient_verification_issuers'
elif 'transaction_account_verification' in key:
keySubject = 'transaction_account_verification_issuers'
elif 'transaction_account_tokenization' in key:
keySubject = 'transaction_account_tokenization_issuers'
elif 'transaction_recipient_payment' in key:
keySubject = 'transaction_recipient_payment_issuers'
elif '_field_results' in key:
if 'transaction_recipient_notification' in key:
keySubject = 'transaction_recipient_notification_field_results'
elif 'transaction_recipient_authentication' in key:
keySubject = 'transaction_recipient_authentication_field_results'
elif 'transaction_recipient_verification' in key:
keySubject = 'transaction_recipient_verification_field_results'
elif 'transaction_account_verification' in key:
keySubject = 'transaction_account_verification_field_results'
elif 'transaction_account_tokenization' in key:
keySubject = 'transaction_account_tokenization_field_results'
elif 'transaction_recipient_payment' in key:
keySubject = 'transaction_recipient_payment_field_results'
print(f'BEFORE ===> {key}')
print(f'AFTER ===> {keySubject}')
可能的方向:
import re
class MainKeyHandleSwitch:
ARRAY_OPTIONS = ['_issuers', '_field_results']
def __init__(self,key):
self._original_key = key
self._array_data = any(substring in key for substring in self.ARRAY_OPTIONS)
self._trimmed_dict = self.trimmed_dict()
@property
def get_trimmed_dict(self):
return self._trimmed_dict
@property
def get_trimmed_key(self):
return self.__get_key_subject__()
def trimmed_dict(self):
trim_dict = dict()
trim_dict['case_one'] = re.search('transaction_recipient_notification+', self._original_key)
trim_dict['case_two'] = re.search('transaction_recipient_authentication+', self._original_key)
trim_dict['case_three'] = re.search('transaction_recipient_verification+', self._original_key)
trim_dict['case_four'] = re.search('transaction_account_verification+', self._original_key)
trim_dict['case_five'] = re.search('transaction_account_tokenization+', self._original_key)
trim_dict['case_six'] = re.search('transaction_recipient_payment+', self._original_key)
return trim_dict
def __get_key_subject__(self):
obj = next(item for item in list(self._trimmed_dict.values()) if item is not None)
if not self._array_data:
return obj.group(0)
else:
if '_issuers' in self._original_key:
return f'{obj.group(0)}_issuers'
elif '_field_results' in self._original_key:
return f'{obj.group(0)}_field_results'
和测试class的代码:
import random
key = random.choice(sampleKeys)
print(f'before ===> {key}')
a = MainKeyHandleSwitch(key)
trimmed_key = a.get_trimmed_key
print(f'after ===> {trimmed_key}')
我看到你的代码中有很多重复,所以我首先想到的是:“我可以使用循环来简化这段代码吗?”答案是肯定的!
由于您的代码重复使用了六个 subjectTypes
并且 keySubject
取决于主题类型,因此创建六个类型的列表然后将 next()
与生成器表达式一起使用应该会简化if
的过多(如果没有任何相关性,则可以使用字典)。此外,除了 array_data
,您还可以使用 if-elif-else
子句来防止额外的块级别。
sampleKeys = [...]
key = random.choice(sampleKeys)
subjectTypes = ['transaction_recipient_notification', 'transaction_recipient_authentication',
'transaction_recipient_verification', 'transaction_account_verification',
'transaction_account_tokenization', 'transaction_recipient_payment']
if '_issuers' in key:
keySubject = next(t + '_issuers' for t in subjectTypes if t in key)
elif '_field_results' in key:
keySubject = next(t + '_field_results' for t in subjectTypes if t in key)
else:
keySubject = next(t for t in subjectTypes if t in key)
print(f'BEFORE ===> {key}')
print(f'AFTER ===> {keySubject}')
如果您正在寻找一种实现 switch 语句的方法,以下是我的解决方法:
首先像这样为开关创建一个辅助函数(我把我的放在我所有项目中使用的“myTools.py”模块中):
def switch(v): yield lambda *c:v in c
它的工作方式是返回一个捕获开关值的函数 (lambda),如果该值在其任何参数中,则 returns 为真。单个 yield 使 switch() 成为可在 for 循环中使用的生成器。 for 循环只会执行一次迭代,但鉴于它仍然是一个循环,它将支持 break 语句和末尾的 else 子句(当没有执行 break 时)。
这允许以与其他语言(例如 C++)中的 switch 语句非常相似的形式使用一次迭代 for 循环:
value = 5
for case in switch(value): # case is actually a function
if case(0): print("None"); break
if case(2,4,6): print("Even"); break
if case(3,5,7): print("Odd"); break
else:
print("invalid value")
通过这种方法,您可以让您的 switch 函数执行任何类型的模式匹配:
def switchAllIn(v): yield lambda *c:all(s in v for s in c)
此版本的 switch 函数检查是否所有 case 参数都在 switch 值中:
value = 'The quick brown fox, jumped over the lazy dogs'
for case in switchAllIn(value):
if case('quick','lazy'): print('oxymoron'); break
if case('quick','fast'): print('redundant'); break
else:
print('nothing special')
你甚至可以让它使用正则表达式:
def switchMatch(v): yield lambda *c:any(re.match(p,v) for p in c)
value = 'The quick brown fox, jumped over the lazy dogs'
for case in switchMatch(value):
if case(r'\bdog\b',r'\bfox\b') and not case('lazy'):
print('lively canine')
break
if case(r'\bquick\b.+\bfox\b'):
print('veloce vulpe')
break
此解决方案具有很大的灵活性。
您实际上不必使用 break,因此您可以遍历多个 case,甚至可以在 if case(...):
块之间执行一些逻辑
您可以使用 and/or 运算符组合大小写,例如 if case(1) or case(3):
使用中断时,您可以嵌套 for case in switch
,而不必为 case
函数使用不同的名称
例如:
for case in switch(letter):
if case('a','b'):
for case in switch(number):
if case(1,2,3): print('vitamin'); break
...
break
if case('c','d'):
...
break
- 您可以将多个 switch 调用与 zip() 结合使用
例如:
for caseL,caseN in zip(switch(L),switch(N)):
if caseL('a','b') and caseN(1,2,3):
print('vitamin')
break
...
- 您可以使用 map()
将开关应用于列表的每个元素
在这种情况下,for 循环将 运行 不止一次,您必须使用 continue 而不是 break:
L = [1,2,3,4,5]
for case in map(switch,L):
if case(1,2,3):
print('low')
continue # using continue instead of break
if case(4,5,6):
print('medium')
continue
print('high')
然而,对于您的特定场景,switch 语句不一定是最佳解决方案。似乎存在前缀和后缀的组合模式,其间有一组有限的关键字。您可以在由前缀、关键字和后缀组成的正则表达式上使用循环来获取 keySubject:
import re
prefixes = ('transaction_recipient_','transaction_account_')
suffixes = ('_issuers','_field_results','') # in priority order
keywords = r'notification|authentication|verification|tokenization|payment'
for suffix in suffixes:
for prefix in prefixes:
pattern = r'\b('+prefix+keywords+suffix+')\b'
m = re.match(pattern,key)
if not m: continue
keySubject = m.group()
break
else: continue; break
print(f'AFTER ===> {keySubject}')
好吧,冒着因不 'trying harder' 而被嘲笑的风险,我有一个场景,我一直在尝试适应 pythonic switch case 语句。我知道 python 在 3.10 中有新的 match
方法,但在我的 AWS 用例中我仅限于 3.8.10。我一直在阅读其他语言的 switch case,我想找到一种 pythonic 方法将以下混乱的 if/elif/else
语句转换为干净的 switch case。我想知道在这种情况下其他人会怎么做
OBJECTIVE:我有一个文件名将传递到此代码序列中,我需要 return 前三项(即 transaction_recipient_verification
、transaction_account_tokenization
, ETC)。有时代码会收到一个包含“field_results”或“发行者”的文件名,我需要确保修剪后的 return 字符串包含相应的大小写。
import random
sampleKeys = [
'transaction_recipient_notification_status_sent/transaction_recipient_notification_status_sent_2021_10_29_12_02_14.snappy',
'transaction_recipient_payment_status_success/transaction_recipient_payment_status_success_2021_10_29_12_02_14.snappy',
'transaction_recipient_verification_rvdm_failure/transaction_recipient_verification_rvdm_failure_2021_10_29_12_02_14.snappy',
'transaction_recipient_verification_rvdm_failure_field_results/transaction_recipient_verification_rvdm_failure_2021_10_29_12_02_14.snappy',
'transaction_recipient_authentication_status_success/transaction_recipient_authentication_status_success_2021_10_29_12_02_14.snappy',
'transaction_recipient_authentication_status_success_field_results/transaction_recipient_authentication_status_success_2021_10_29_12_02_14.snappy',
'transaction_account_tokenization_success/transaction_account_tokenization_success_2021_10_29_12_02_14.snappy',
'transaction_account_tokenization_success_issuers/transaction_account_tokenization_success_2021_10_29_12_02_14.snappy',
'transaction_recipient_payment_status_terminated/transaction_recipient_payment_status_terminated_2021_10_29_12_02_14.snappy',
'transaction_recipient_verification_rvdm_success/transaction_recipient_verification_rvdm_success_2021_10_29_12_02_14.snappy',
'transaction_recipient_verification_rvdm_success_field_results/transaction_recipient_verification_rvdm_success_2021_10_29_12_02_14.snappy',
'transaction_recipient_notification_status_received/transaction_recipient_notification_status_received_2021_10_29_12_02_14.snappy',
'transaction_recipient_authentication_status_success/transaction_recipient_authentication_status_success_2021_10_29_11_17_45.snappy'
]
key = random.choice(sampleKeys)
array_data = any(substring in key for substring in ['_issuers', '_field_results'])
if not array_data:
if 'transaction_recipient_notification' in key:
keySubject = 'transaction_recipient_notification'
elif 'transaction_recipient_authentication' in key:
keySubject = 'transaction_recipient_authentication'
elif 'transaction_recipient_verification' in key:
keySubject = 'transaction_recipient_verification'
elif 'transaction_account_verification' in key:
keySubject = 'transaction_account_verification'
elif 'transaction_account_tokenization' in key:
keySubject = 'transaction_account_tokenization'
elif 'transaction_recipient_payment' in key:
keySubject = 'transaction_recipient_payment'
else:
if '_issuers' in key:
if 'transaction_recipient_notification' in key:
keySubject = 'transaction_recipient_notification_issuers'
elif 'transaction_recipient_authentication' in key:
keySubject = 'transaction_recipient_authentication_issuers'
elif 'transaction_recipient_verification' in key:
keySubject = 'transaction_recipient_verification_issuers'
elif 'transaction_account_verification' in key:
keySubject = 'transaction_account_verification_issuers'
elif 'transaction_account_tokenization' in key:
keySubject = 'transaction_account_tokenization_issuers'
elif 'transaction_recipient_payment' in key:
keySubject = 'transaction_recipient_payment_issuers'
elif '_field_results' in key:
if 'transaction_recipient_notification' in key:
keySubject = 'transaction_recipient_notification_field_results'
elif 'transaction_recipient_authentication' in key:
keySubject = 'transaction_recipient_authentication_field_results'
elif 'transaction_recipient_verification' in key:
keySubject = 'transaction_recipient_verification_field_results'
elif 'transaction_account_verification' in key:
keySubject = 'transaction_account_verification_field_results'
elif 'transaction_account_tokenization' in key:
keySubject = 'transaction_account_tokenization_field_results'
elif 'transaction_recipient_payment' in key:
keySubject = 'transaction_recipient_payment_field_results'
print(f'BEFORE ===> {key}')
print(f'AFTER ===> {keySubject}')
可能的方向:
import re
class MainKeyHandleSwitch:
ARRAY_OPTIONS = ['_issuers', '_field_results']
def __init__(self,key):
self._original_key = key
self._array_data = any(substring in key for substring in self.ARRAY_OPTIONS)
self._trimmed_dict = self.trimmed_dict()
@property
def get_trimmed_dict(self):
return self._trimmed_dict
@property
def get_trimmed_key(self):
return self.__get_key_subject__()
def trimmed_dict(self):
trim_dict = dict()
trim_dict['case_one'] = re.search('transaction_recipient_notification+', self._original_key)
trim_dict['case_two'] = re.search('transaction_recipient_authentication+', self._original_key)
trim_dict['case_three'] = re.search('transaction_recipient_verification+', self._original_key)
trim_dict['case_four'] = re.search('transaction_account_verification+', self._original_key)
trim_dict['case_five'] = re.search('transaction_account_tokenization+', self._original_key)
trim_dict['case_six'] = re.search('transaction_recipient_payment+', self._original_key)
return trim_dict
def __get_key_subject__(self):
obj = next(item for item in list(self._trimmed_dict.values()) if item is not None)
if not self._array_data:
return obj.group(0)
else:
if '_issuers' in self._original_key:
return f'{obj.group(0)}_issuers'
elif '_field_results' in self._original_key:
return f'{obj.group(0)}_field_results'
和测试class的代码:
import random
key = random.choice(sampleKeys)
print(f'before ===> {key}')
a = MainKeyHandleSwitch(key)
trimmed_key = a.get_trimmed_key
print(f'after ===> {trimmed_key}')
我看到你的代码中有很多重复,所以我首先想到的是:“我可以使用循环来简化这段代码吗?”答案是肯定的!
由于您的代码重复使用了六个 subjectTypes
并且 keySubject
取决于主题类型,因此创建六个类型的列表然后将 next()
与生成器表达式一起使用应该会简化if
的过多(如果没有任何相关性,则可以使用字典)。此外,除了 array_data
,您还可以使用 if-elif-else
子句来防止额外的块级别。
sampleKeys = [...]
key = random.choice(sampleKeys)
subjectTypes = ['transaction_recipient_notification', 'transaction_recipient_authentication',
'transaction_recipient_verification', 'transaction_account_verification',
'transaction_account_tokenization', 'transaction_recipient_payment']
if '_issuers' in key:
keySubject = next(t + '_issuers' for t in subjectTypes if t in key)
elif '_field_results' in key:
keySubject = next(t + '_field_results' for t in subjectTypes if t in key)
else:
keySubject = next(t for t in subjectTypes if t in key)
print(f'BEFORE ===> {key}')
print(f'AFTER ===> {keySubject}')
如果您正在寻找一种实现 switch 语句的方法,以下是我的解决方法:
首先像这样为开关创建一个辅助函数(我把我的放在我所有项目中使用的“myTools.py”模块中):
def switch(v): yield lambda *c:v in c
它的工作方式是返回一个捕获开关值的函数 (lambda),如果该值在其任何参数中,则 returns 为真。单个 yield 使 switch() 成为可在 for 循环中使用的生成器。 for 循环只会执行一次迭代,但鉴于它仍然是一个循环,它将支持 break 语句和末尾的 else 子句(当没有执行 break 时)。
这允许以与其他语言(例如 C++)中的 switch 语句非常相似的形式使用一次迭代 for 循环:
value = 5
for case in switch(value): # case is actually a function
if case(0): print("None"); break
if case(2,4,6): print("Even"); break
if case(3,5,7): print("Odd"); break
else:
print("invalid value")
通过这种方法,您可以让您的 switch 函数执行任何类型的模式匹配:
def switchAllIn(v): yield lambda *c:all(s in v for s in c)
此版本的 switch 函数检查是否所有 case 参数都在 switch 值中:
value = 'The quick brown fox, jumped over the lazy dogs'
for case in switchAllIn(value):
if case('quick','lazy'): print('oxymoron'); break
if case('quick','fast'): print('redundant'); break
else:
print('nothing special')
你甚至可以让它使用正则表达式:
def switchMatch(v): yield lambda *c:any(re.match(p,v) for p in c)
value = 'The quick brown fox, jumped over the lazy dogs'
for case in switchMatch(value):
if case(r'\bdog\b',r'\bfox\b') and not case('lazy'):
print('lively canine')
break
if case(r'\bquick\b.+\bfox\b'):
print('veloce vulpe')
break
此解决方案具有很大的灵活性。
您实际上不必使用 break,因此您可以遍历多个 case,甚至可以在
if case(...):
块之间执行一些逻辑您可以使用 and/or 运算符组合大小写,例如
if case(1) or case(3):
使用中断时,您可以嵌套
for case in switch
,而不必为case
函数使用不同的名称
例如:
for case in switch(letter):
if case('a','b'):
for case in switch(number):
if case(1,2,3): print('vitamin'); break
...
break
if case('c','d'):
...
break
- 您可以将多个 switch 调用与 zip() 结合使用
例如:
for caseL,caseN in zip(switch(L),switch(N)):
if caseL('a','b') and caseN(1,2,3):
print('vitamin')
break
...
- 您可以使用 map() 将开关应用于列表的每个元素
在这种情况下,for 循环将 运行 不止一次,您必须使用 continue 而不是 break:
L = [1,2,3,4,5]
for case in map(switch,L):
if case(1,2,3):
print('low')
continue # using continue instead of break
if case(4,5,6):
print('medium')
continue
print('high')
然而,对于您的特定场景,switch 语句不一定是最佳解决方案。似乎存在前缀和后缀的组合模式,其间有一组有限的关键字。您可以在由前缀、关键字和后缀组成的正则表达式上使用循环来获取 keySubject:
import re
prefixes = ('transaction_recipient_','transaction_account_')
suffixes = ('_issuers','_field_results','') # in priority order
keywords = r'notification|authentication|verification|tokenization|payment'
for suffix in suffixes:
for prefix in prefixes:
pattern = r'\b('+prefix+keywords+suffix+')\b'
m = re.match(pattern,key)
if not m: continue
keySubject = m.group()
break
else: continue; break
print(f'AFTER ===> {keySubject}')