如何使一个函数可以处理单个输入或输入列表

时间:2018-08-24 20:41:27

标签: python function

我将用几个仅对数字取平方的过于简单的函数来说明我的问题。但这是编写我想了解的功能的一般最佳实践。

假设我有一个要平方的数字,我可以编写以下函数。

def square (x):
    y = x**2
    return y

如果我有一个数字列表,并且想获得每个元素都平方的列表,我可以使用

def square (x_list):
    y_list = []
    for x in x_list:
        y_list.append( x**2 )
    return y_list

但是我只想编写一个可以处理这两种情况的函数。它将查看输入是数字还是列表,并采取相应措施。我可以使用type来检测类型,但是我想知道最Python的方式是什么。

6 个答案:

答案 0 :(得分:2)

使用numpy非常简单。对于多个元素,请将其作为数组。对于单个元素,将直接应用该功能。

import numpy as np

def square(a):
    return a**2

a = np.array([2,3,4,5])
print(square(a)) # array([ 4,  9, 16, 25])

b = 9
print(square(b)) # 81

答案 1 :(得分:2)

我同意@Bryan Oakley的回答,最好编写代码以仅接受单个参数类型。话虽如此,我想我将举一个处理可变数量输入参数的函数示例:

def square(*args):

    return [arg**2 for arg in args]

请注意,这将始终返回列表:

y = square(2,4,6,8)

y = square(4)

收益:

[4, 16, 36, 64]
[16]

答案 2 :(得分:1)

您可以检查传入参数的类型并采取相应措施:

# check the variable instance type
def square (x):
    """Returns squares of ints and lists of ints - even if boxed inside each other.
    It uses recursion, so do not go too deep ;o)"""

    if isinstance(x,int):
        return x**2

    elif isinstance(x,list):
        return [square(b) for b in x] #  recursion for lists of ints/lists of ints

    else:
        raise ValueError("Only ints and list of ints/list of ints allowed")


print(square(4))
print(square([2,3,4]))
print(square([2,3,[9,10],11]))

try:
    print(square(2.6))
except ValueError as e:
    print(e)

输出:

16
[4, 9, 16]
[4, 9, [81, 100], 121]

Only ints and list of ints/list of ints allowed

答案 3 :(得分:1)

将参数作为列表输入处理,如果不是,则处理异常。

  

EAFP   寻求宽恕比允许容易。这种通用的Python编码风格假定有效键或属性的存在,并且在假定证明为假的情况下捕获异常。这种干净快捷的样式的特点是存在许多try和except语句。该技术与许多其他语言(例如C)常见的LBYL风格形成对比。docs

def square(x):    
    try:
        y = [e ** 2 for e in x]
    except TypeError:
        y = x ** 2
    return y

square(2)
# Out: 4
square([2, 3])
# Out: [4, 9]

答案 4 :(得分:1)

正如其他答案所解释的那样,这可能不是一个很好的设计。

首先,“数字”可以是intint的某些用户定义子类,或者是float或某些用户定义的Quaternion类型。通常,您只需要使用鸭子输入即可:x ** 2有效,然后x就像数字一样嘎嘎作响,就足够了。

但是一个整数列表并不像一个整数那样震撼。那么,你能做什么?

通常,您会希望显式地遍历它们:

>>> xs = [1, 2, 3]
>>> sqs = [square(x) for x in xs]

…或编写一个执行该操作的函数:

>>> def squares(xs): return [square(x) for x in xs]
>>> sqs = squares(xs)

…或使用知道如何向量化数学运算符的类型:

>>> xs = np.array([1, 2, 3])
>>> sqs = square(xs)

实际上,即使您要做要处理两种不同的类型,您也经常可以依赖鸭子输入:

def square(x):
    try:
        return x**2
    except ValueError:
        return [i**2 for i in x]

这将对所有数字进行平方运算以求平方,并且对平方所有不存在的元素进行迭代,并为失败的事物引发合理的例外(要么是因为它不可迭代,要么是因为它元素不可平方)。


有时候,您确实确实需要进行类型切换。但是您仍然希望尽可能地避开鸭式输入法,这意味着使用isinstance(因此,例如int的用户子类型仍然算作数字),通常使用abstract base classes(因此,例如,用户Quaternion类型仍然算作数字)。

在这种情况下,这意味着要么专门对待numbers并假设其他任何事情都是可迭代的:

def square(x):
    if isinstance(x, numbers.Number):
        return x**2
    else:
        return [i**2 for i in x]

…或特别对待iterables并假设其他所有内容都是数字:

def square(x):
    if isinstance(x, collections.abc.Iterable):
        return [i**2 for i in x]
    else:
        return x**2

或者特别对待并且将其他所有错误称为:

def square(x):
    if isinstance(x, numbers.Number):
        return x**2
    elif isinstance(x, collections.abc.Iterable):
        return [i**2 for i in x]
    raise ValueError(f"'{type(x).__name__}' instance is not a number or numbers")

答案 5 :(得分:0)

您可以编写一行返回,但可以使用以下类型:

REPLACE