你的函数基本上是这样做的:
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 的元素都是布尔值,这意味着将它们与按位与组合与将它们与逻辑与组合是相同的,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 可以只包含键,这将允许我们查找参数值和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)]
编辑:根据下面的 cmets,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])