我有Python v2.7。
我想创建一个接受None
,str
或list
的函数。我需要在参数上添加一些内容,以便我按照以下方式创建一个辅助函数:
def _append_or_set(x, to_append):
if x is None:
return to_append
if type(x) is str:
return [x, to_append]
if type(x) is list:
x.append(to_append)
return x
(显然这不是很好的编程,并且没有错误处理等,但它只是为了说明。)
但是知道Python,已经有了一种巧妙的方法。它是什么?
我这样做是因为我想过滤数据集。调用者传递None(即返回所有行)或字符串(只是与此值匹配的行)或列表(匹配这些值的任何的行)
无论调用者要求什么,我总是需要包含至少包含foo
的行。所以我这样做:
def _filter_data(filter_by):
filter_by = _append_or_set(filter_by, 'foo')
return do_my_filtering(filter_by)
答案 0 :(得分:2)
可能我仍然可能无法理解你想要的东西,但我认为这样可行:
>>> def _append_or_set(x, to_append):
... try:
... x.append(to_append)
... except AttributeError:
... if x:
... x = [x, to_append]
... else:
... x = to_append
... finally:
... return x
...
>>> _append_or_set([5,3,4], 6)
[5, 3, 4, 6]
>>> _append_or_set("this is x,", "this is appended")
['this is x,', 'this is appended']
>>> _append_or_set(None, "hello")
'hello'
通过使用try...except...finally
,您可以避免显式类型检查,这通常被认为是不好的做法。
第一个try
假设x
是一个列表。它不是(如果x.append()
中断),那么它必须是一个字符串,或None
。一个简单的if
将确定它是什么。
答案 1 :(得分:2)
虽然你的函数可以正常工作(除了你应该使用isinstance
和elif
),我确实看到它有问题,那就是它没有真正的一致接口。假设to_append
是一个字符串,有三种不同的情况:
None
,函数返回一个字符串。相反,您应该尝试保持界面一致。例如,始终返回一个列表,不要触摸参数本身:
def _append_or_set(x, to_append):
if x is None:
return [to_append]
elif isinstance(x, (list, tuple, set)): # also accept tuples and sets
return list(x) + [to_append]
else:
# assume that anything else is fine as the first element
return [x, to_append]
答案 2 :(得分:0)
Python 3.4在singledispatch
模块中添加了functools
装饰器,让您可以使用更多通用编程风格:
@singledispatch
def append_or_set(x, to_append):
raise RuntimeError("Unregistered type")
# This one isn't strictly necessary; you could just have the default behavior
# in the original function be to return the value to append if no other types
# will be supplied.
@append_or_set.register(type(None))
def append_or_set(x, to_append):
return to_append
@append_or_set.register(str)
def append_or_set(x, to_append):
return [x, to_append]
@append_or_set.register(list)
def append_or_set(x, to_append):
x.append(to_append)
return x
你可以找到更多信息in the docs,但最相关的一点是那里没有列出的:functools.singledispatch
的实现都是Python,所以即使你使用的是Python 2.7,你也可以向后移植Python 3.4版本functools.py
中的必要代码并使用它。它应该不会太麻烦,因为与singledispatch
相关联的函数似乎没有使用Python 3中的任何功能,即使没有__future__
导入也与2.7中的功能明显不同(尽管我可能这是错误的,因为我没有测试过它。)
另外,正如其他人所说的那样,最好使返回值更加一致,除非需要,否则应避免改变参数,例如: return to_append
将成为return [to_append]
,x.append(to_append);return x
将成为return x + [to_append]
。