给出n个变量的语句链式的pythonic方法是什么?

时间:2017-04-20 16:36:06

标签: python python-3.x if-statement

我将以下函数作为脚本inspired by this的一部分:

def view(a='', b='', c=''):
    if a=='All' and b=='All' and c=='All': return df 
    if a=='All' and c=='All' and b!='All': return df[(df['b']==b)]
    if a!='All' and c=='All' and b=='All': return df[(df['a']==a)]
    if a=='All' and c!='All' and b=='All': return df[(df['c']==c)]
    if a=='All' and c!='All' and b!='All': return df[(df['c']==c) & (df['b']==b)]                                                        
    if a!='All' and c=='All' and b!='All': return df[(df['a']==a) & (df['b']==b)]                                                                     
    if a!='All' and c!='All' and b=='All': return df[(df['a']==a) & (df['c']==c)]                                                                 
    return df[(df['a']==a) & (df['b']==b) & (df['c']==c)]

有没有一种很好的方法来编写带有一个漂亮的pythonic表达式的所有链接if语句。如果对n个变量进行推广,则给出答案。

注意: Perhaps related to this question,但我仍然无法弄明白。

2 个答案:

答案 0 :(得分:0)

你的功能基本上是这样做的:

if all parameters are 'All':
    return df
else:
    Take all the non-'All' parameters
    Test if each one is equal to df['name_of_parameter']
    Bitwise-AND them together
    Return df[result of previous line]

让我们首先列出所有非'全部'参数:

notall = [x for x in [a,b,c] if x != 'All']
if not notall:
    return df
else:
    ???

障碍#1:我们现在已经忘记了哪个值与哪个参数相关。为什么我们需要知道?这样我们就可以将参数与df的正确元素进行比较。我们可以通过不仅存储参数来解决这个问题。 notall中的值以及它们的名称:

notall = [(x, name) for (x, name) in [(a, 'a'), (b, 'b'), (c, 'c')] if x != 'All']
if not notall:
    return df
else:
    ???

两次写出每个参数的名称很难看,但它要么是这个,要么是locals和/或**kwargs的顽皮。

通过这种方式,对df元素的比较很容易:

 compared = [df[name] == x for (x, name) in notall]

现在,我们如何和他们在一起?我们可以使用functools.reduce()operator.and_,但是(除非您重载==以返回非布尔值,我希望您没有这样做),元素compared都是布尔值,这意味着将它们与按位AND组合与将它们与逻辑AND组合相同,并且Python已经具有以下功能:all()

return df[all(compared)]

全部放在一起:

def view(a='', b='', c=''):
    notall = [(x, name) for (x, name) in [(a, 'a'), (b, 'b'), (c, 'c')] if x != 'All']
    if not notall:
        return df
    else:
        compared = [df[name] == x for (x, name) in notall]
        return df[all(compared)]

或者,更紧凑:

def view(a='', b='', c=''):
    notall = [(x, name) for (x, name) in [(a, 'a'), (b, 'b'), (c, 'c')] if x != 'All']
    if not notall:
        return df
    else:
        return df[all(df[name] == x for (x, name) in notall)]

现在,关于前面提到的那种顽皮:如果所有参数都在dict中,那么notall可以只包含键,这样我们就可以查找参数值和{ {1}}值而不重复(太多)。我们如何获得df中的所有参数?使用dict

**kwargs

(请注意使用def view(**kwargs): notall = [name for name in NAMES if kwargs.get(name, '') != 'All'] 为参数提供默认值。)但get应该是什么?它不能是NAMES,因为它只包含用户传入的参数,这些参数可能不是全部参数(甚至可能包含我们不期望的密钥!)。选项1是在某处写出参数名称列表并使用:

kwargs.keys()

或者,如果NAMES = ['a', 'b', 'c'] 的键恰好与函数参数的所需名称相同,我们可以使用df

df.keys()

或略短:

    notall = [name for name in df.keys() if kwargs.get(name, '') != 'All']

在此之后,我们只需要更新 notall = [name for name in df if kwargs.get(name, '') != 'All'] 元素的使用方式,改变这一点:

notall

到此:

return df[all(df[name] == x for (x, name) in notall)]

(请注意,我们仍需要继续使用return df[all(df[name] == kwargs.get(name, '') for name in notall)] 来设置默认值。)

将它们全部重新组合在一起:

get

或者,如果参数名称与NAMES = ['a', 'b', 'c'] def view(**kwargs): notall = [name for name in NAMES if kwargs.get(name, '') != 'All'] if not notall: return df else: return df[all(df[name] == kwargs.get(name, '') for name in notall)] 的键相同:

df

编辑:基于以下评论,显然def view(**kwargs): notall = [name for name in df if kwargs.get(name, '') != 'All'] if not notall: return df else: return df[all(df[name] == kwargs.get(name, '') for name in notall)] 的值会覆盖df,因此它不会返回布尔值。幸运的是,如上所述,这只需要改变这一点:

==

到此:

return df[all(df[name] == kwargs.get(name, '') for name in notall)]

答案 1 :(得分:0)

这应该可以解决问题:

import itertools, functools
from operator import eq, ne, and_

def view(*args):
    Eq, Ne = functools.partial(eq, 'All'), functools.partial(ne, 'All')

     if all(Eq(var) for var in args):
         return df 

    for cond, ret in itertools.product((Eq, Ne), len(args)):
        if all(fun(var) for var, fun in zip(args, cond)):
            index = functools.reduce(and_, (df[var] == var for var, fun in cond if fun == Ne))
            return df[index]

唯一的问题是我没有简单的方法知道您当前正在使用的变量的名称。这就是我使用df[var] == var的原因。

例如,通过使每个变量都带有它的名称,这相对容易修复。因此,基本上,每个变量都是一个元组a = (variable, "variable")