"如何以优雅的方式将n个变量链接在一起编写if语句?"

2024-09-28 21:53:43 发布

您现在位置:Python中文网/ 问答频道 /正文

我将以下函数作为脚本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,但我还是搞不懂。你知道吗


Tags: and方法函数脚本viewdfbyreturn
2条回答

您的功能基本上是这样:

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]

让我们先从所有非“all”参数的列表开始重写:

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]

现在,我们如何和他们在一起?我们可以使用^{}^{},但是(除非您重载了==以返回一个非布尔值,我希望您没有这样做),compared的元素都是布尔值,这意味着将它们与按位and组合与将它们与逻辑and组合相同,Python已经有了一个函数:^{}。你知道吗

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可以只包含键,这将允许我们查找参数值和df值,而不会重复我们自己(太多)。如何获得dict中的所有参数?使用**kwargs

def view(**kwargs):
    notall = [name for name in NAMES if kwargs.get(name, '') != 'All']

(注意使用get为参数提供默认值)但是NAMES应该是什么?它不能是kwargs.keys(),因为它只包含用户传入的参数,可能不是所有参数(甚至可能包含我们不期望的键!)。选项1是在某处写出一个参数名列表,并使用:

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

对此:

import functools
import operator

return functools.reduce(operator.and_, [df[name] == kwargs.get(name, '') for name in notall])

这应该可以做到:

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")。你知道吗

相关问题 更多 >