简化`if ... elif..else`条件

时间:2016-05-03 14:41:19

标签: python dictionary flags

如果我有多个条件(嵌套和/或其他)与布尔(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']}

如果我通过dict:

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')

5 个答案:

答案 0 :(得分:1)

如果高效完成,使用'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,将在命名空间中创建 变量,并为其分配值{{1 }}

希望这会有所帮助。

答案 1 :(得分:0)

这里的代码就像你能得到的一样简单。

您可以压缩的一种方法是更改​​最后一个分支:

elif flag2:
    if flag3:
        do a fourth thing

elif flag2 and flag3:
    do a fourth thing

答案 2 :(得分:0)

您可以在标志上使用迭代器。字典也可以工作,具体取决于你的标志是什么,但是如果你的标志像x==1, y==10, z=='a'那样可以全部评估为TrueFalse (因为密钥只能是唯一的)。如果你的标志是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

答案 3 :(得分:0)

你考虑过重构吗?一个编写良好的函数应该做一件事,事实上你有三个标志表明这个代码块将至少做三件事,这给测试,代码可读性等带来了很多麻烦。

您确定无法将其重构为三个或更多方法,请检查开头的标记并启动相应的方法。

答案 4 :(得分:0)

您可以使用词典:

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

然后拨打d[(flag1,flag2,flag3)]() 如果您需要工业数量的if / elses,否则只需尝试进行正确的简化。

当然,如果你再次测试相同的入口变量,或者使用不同参数作为输出应用相同的函数,那么你可以通过用实际数据替换布尔值和函数来进一步简化。