如何将Python中的单一值和列表值处理得一样?
我经常遇到这样的问题:我在创建一个函数,这个函数需要对一个值进行一系列操作,这个值可以是单个值,也可以是一个值的列表。
有没有更优雅的方法来实现这个呢:
def convert_val(val):
do a series of things to each value, whether list or single val
return answer or list of answers
而不是我现在这样做?:
def convert_val(val):
if isinstance(val, list):
... do a series of things to each list item,
return a list of answers
else:
... do the same series, just on a single value
return a single answer
一种解决方案是创建一个叫做 sub_convert() 的函数,它可以执行这系列操作,然后根据传入的类型,在 convert() 中调用它一次或多次。
另一种方法是创建一个单一的 convert() 函数,它可以接受参数(值,sub_convert())。
有没有其他更简洁、更优雅的建议,最好是都放在一个函数里?
(我在这里搜索过几次,看看我的问题是否已经被解决。如果已经解决了,我很抱歉。)
谢谢,
JS
3 个回答
我来晚了,不太确定这是不是提问者想要的。
我更喜欢把实现的细节藏在函数内部。调用这个函数的人不应该关心里面发生了什么。
def convert_val(val):
values = []
values.extend(val)
for value in values:
# do things to each list item,
return a list of answers
这样的话,convert_val
函数会把 val
放进 values
列表里(如果它不是一个列表的话),或者把 val
的所有值放进 values
列表里。
而且,最终应该能稳定地返回一个列表(因为你会用相同的逻辑)。
最后:
assert convert_val([1]) == convert_val(1)
你需要调整你的设计,让这个函数的使用方式都正确。
拉尔夫·瓦尔多·爱默生曾说过:“愚蠢的一致性是小心眼者的鬼怪,受到小政治家、哲学家和神职人员的崇拜。”
我们这里不是在说愚蠢的一致性。你可能遇到了一个设计问题,因为这个函数的使用方式不一致。
选项1:不要在x
不是列表的情况下调用convert_val( x )
。这样做:convert_val( [x] )
。不要去修这个函数,而是修正所有使用这个函数的地方。一致性有助于减少错误。
选项2:改变convert_val
的设计,使用多个位置参数。这种方法不太通用。
def convert_val( *args ):
whatever it's supposed to do to the arguments.
然后把你提供列表的地方改成convert_val( *someList )
。这样做是可以的,可能更接近你的初衷。
注意:
你可以使用warnings
模块来找到你的设计错误。
def convert_val( arg ):
if isinstance( arg, collections.Sequence ):
return convert_val_list( arg )
else:
warnings.warn( "Fix this" )
return convert_val_list( [arg] )[0]
def convert_val_list( arg ):
assert isinstance( arg, collections.Sequence )
the original processing
一旦你修复了所有设计问题,你就可以这样做:
convert_val = convert_val_list
然后删除原来的函数。
如果一个函数对单个值和列表都能正常工作,那么从逻辑上讲,这个函数对列表中某个项目的结果就不应该受到列表中其他项目的影响。
举个例子,a
和 b
最后应该是一样的:
items = [1, 2]
a = convert_val(items)
b = map(convert_val, items)
这个例子已经给出了一个提示:调用这个函数的人知道传入的是一个列表还是一个单独的值。当传入一个单独的值时,函数可以直接使用。当传入一个列表时,可以很容易地加上一个 map
调用,这样就能更清楚地看到调用者在做什么。
所以,你描述的这个函数根本就不应该存在!