簡體   English   中英

簡化if ... elif..else條件

[英]Simplifying `if…elif..else` conditions

如果我具有布爾( FalseTrue )輸出的多個條件(嵌套和/或其他條件); 如何進一步簡化代碼,使其更高效,更全面,更優雅?

例如,在以下情況下:

if condition_1:
    if condition_2:
        # do one thing
        pass
    elif condition_3:
        # do another thing
        pass
    else:
        # do a third thing
        pass

elif condition_2:
    if condition_3:
        # do a fourth thing
        pass

等等。

這是我的考試項目,因此沒有得到太多幫助,我將嘗試解釋我的代碼應該做什么。 我基本上想瀏覽一個數據集,尋找不同的東西。 讓我們說它是一個字典,像這樣:

myDict = {'a': ['b', 'c'], 'b': ['c', 'd']}

如果我通過字典:

for item, element in myDict.items():
    for letter in element:
        if letter == 'd':
            dflag = True
        if letter == 'c':
            cflag = True

    if cflag:
        if dflag:
            print('cd!')
        else:
            print('only c')

如果有效地使用'if','elif'和'else'也不錯。 但總的來說,您問題的答案實際上取決於個人情況。

話雖如此,但是,做到這一點的一種方法是將您的條件放入dict (如您自己在標簽中突出顯示的那樣)。

這里有一些例子:

作為一個dict

conditions = {
    1: 'One',
    2: 'Two',
    3: 'Three',
    4: 'Four',
    5: lambda x: x**2  # Can be substituted with actual functions defined elsewhere.
}

x = 3

if x in conditions.keys():
    print(conditions[x])

返回:

Three

或對於函數:

x = 5

if x in conditions.keys():
    func = conditions[x]
    print(func(x))

返回:

25

使用類似於switch...case的函數:

為了更加清楚,並使用switch...case語句,您可以執行以下操作:

def switch(case):
    conditions = {
        1: 'One',
        2: 'Two',
        3: 'Three',
        4: 'Four',
        5: lambda x: x**2  
    }

    return condition[case] if case in conditions else False

它是這樣運行的:

>>> print(switch(2))
2

或對於不存在的物品:

>>> print(switch(6))
False

在您的示例上的實現:

switch...case功能裝飾器(包裝器)

因此,為了解決您添加的示例,我們可以執行以下操作:

首先,我們需要一個通用的開關/外殼裝飾器:

def switch_case(switch):
    def switcher(func):
        def case(case):
            return switch[case](case) if case in switch else None
        return case 
    return switcher

然后,我們需要一個關於條件的字典,這是您的示例中給出的字典:

# Define the conditions in a dict.
conditions = {
    'd': lambda x: True if 'd' else False,  # You can say: True if 'a' or 'b' else False
    'c': lambda x: True if 'c' else False  
}

現在,我們根據您的條件創建裝飾好的開關盒功能:

@switch_case(conditions)
def my_conditions(case):
    return case

然后,我們指定元素,或從文件,數據庫或任何內容中讀取它們:

# Elements to be tested as string.
# It can be any flattened (not nested) iterable (str, tuple, list, numpy.array, etc.)
myDict = {'a': ['b', 'c'], 'b': ['c', 'd']}
elements = sum(myDict.values(), [])  # Returns a flattened lists of values. 

根據條件評估元素(生成器對象)。

verdicts = map(my_conditions, elements)

將元素匹配到相應的評估結果(生成器對象)。

status = zip(elements, verdicts)

現在,我們可以積極地調節輸出(丟棄None粘滯),並創建一個dict ,其中鍵是元素,值是其條件的狀態。

passed = {key+'flag': val for key, val in status if val is not None}

print(passed)
# output: {'cflag': True, 'dflag': True}

作為變量添加到名稱空間

此時,您可以按原樣使用dict; 但是,如果您堅持將其添加到名稱空間中,則方法如下:

# Rename values and add them to the name space.
locals().update(passed)

測試

最后,讓我們測試並確保這些值存在於本地名稱空間中(注意,我們之前沒有實現任何這些名稱)。 因此,如果條件為序列中的特定字符返回了True值,則將創建一個變量:

>>> print(dflag)  # We had 'd' in `myDict` values.
True

另一方面,如果條件返回None ,則命名空間中將沒有值。

>>> print(aflag)  # We didn't have 'a' in `myDict` values.
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-25-26f7e9594747> in <module>()
     24
---> 25 print(aflag)

NameError: name 'aflag' is not defined

注意 :在現有結構下,如果條件返回False則將在名稱空間中創建一個變量, 為其分配值False

希望這可以幫助。

您的代碼在這里盡可能簡單。

冷凝的一種方法是將最后一個分支更改為:

elif flag2:
    if flag3:
        do a fourth thing

elif flag2 and flag3:
    do a fourth thing

您可以在標志上使用迭代器。 字典也可以工作,具體取決於您的標志是什么,但是如果您的標志是x==1, y==10, z=='a'都可以評估為True或,則它並沒有真正的幫助 False (因為密鑰只能是唯一的)。 如果您的標志采用a == b的形式,則可能必須使用某種迭代器。

def f(): print('f')
def g(): print('g')
def h(): print('h')

y = 3
x = 2

flags = [
    # Outer condition
    (y==1, (
        # Inner conditions and actions
        (x==1, f), (x==2, g), (x==3, h)
     )),
    (y==3, (
        (x==1, g), (x==2, f), (x==3, h)
    ))
]
# Using next ensures that the rest of the flags/actions aren't even evaluated,
# the same way an if/elif would work
_, inner_flags_and_actions = next(
   (flag, inner) for (flag, inner) in flags if flag
)
_, action = next(
    (flag, action) for (flag, action) in inner_flags_and_actions if flag
)

# By now you have reached the action you want to take.
action()

打印: f

您是否考慮過重構? 一個編寫良好的函數應該做一件事,事實上,您有三個標志表明該代碼塊將至少要做三件事,這給測試,代碼可讀性等帶來了很多麻煩。

您確定無法將其重構為三個或更多方法,請檢查開頭的標志並啟動相應的方法。

您可以使用dict:

d = { (False, False, False) : f1,
(False, False, True) : f2,
(False, True, False) : f3,
(False, True, True) : f4
...

然后調用d[(flag1,flag2,flag3)]()這是如果您需要工業級的if / elses,否則請嘗試進行正確的簡化。

當然,如果您要再次測試相同的輸入變量,或者將具有不同參數的相同函數應用為輸出,則可以通過用實際數據替換布爾值和函數來進一步簡化操作。

暫無
暫無

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

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