簡體   English   中英

Python Switch/Case 語句適配

[英]Python Switch/Case Statement Adaptation

好吧,冒着因為沒有“更努力”而被嘲笑的風險,我有一個場景,我一直在嘗試適應 pythonic switch case 語句。 我知道 python 在 3.10 中有新的match方法,但在我的 AWS 用例中我僅限於 3.8.10。 我一直在閱讀其他語言的 switch case,我想找到一種 pythonic 方法將以下混亂的if/elif/else語句轉換為干凈的 switch case。 我想知道在這種情況下其他人會做什么

目標:我有一個文件名將被傳遞到這個代碼序列中,我需要返回前三個項目(即transaction_recipient_verificationtransaction_account_tokenization等)。 有時代碼會收到一個包含“field_results”或“issuers”的文件名,我需要確保修剪后的返回字符串包含相應的案例。

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'        

以及測試類的代碼:

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的過度豐富(如果沒有任何相關性,字典可以代替)。 此外,您可以使用if-elif-else子句代替array_data來防止額外的塊級別。

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),如果該值在其任何參數中,則返回 True。 單個 yield 使 switch() 成為可用於 for 循環的生成器。 for 循環只會執行一次迭代,但鑒於它仍然是一個循環,它將支持 break 語句和最后的 else 子句(當沒有執行任何中斷時)。

這允許以與其他語言(例如 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,因此您可以通過多個案例,甚至在if case(...):塊之間執行一些邏輯

  • 您可以將案例與和/或運算符結合起來,例如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}')

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM