当类型未知时附加到python参数

时间:2014-04-10 12:10:49

标签: python

我有Python v2.7。

我想创建一个接受Nonestrlist的函数。我需要在参数上添加一些内容,以便我按照以下方式创建一个辅助函数:

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)

3 个答案:

答案 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)

虽然你的函数可以正常工作(除了你应该使用isinstanceelif),我确实看到它有问题,那就是它没有真正的一致接口。假设to_append是一个字符串,有三种不同的情况:

    传递
  1. None,函数返回一个字符串。
  2. 传递一个字符串,该函数返回一个2元素列表。
  3. 传递一个列表,该函数会附加到列表并返回它。原始传递的列表也已更改(表示对参数可能产生的副作用)。
  4. 相反,您应该尝试保持界面一致。例如,始终返回一个列表,不要触摸参数本身:

    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]