我将用几个仅对数字取平方的过于简单的函数来说明我的问题。但这是编写我想了解的功能的一般最佳实践。
假设我有一个要平方的数字,我可以编写以下函数。
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的方式是什么。
答案 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)
正如其他答案所解释的那样,这可能不是一个很好的设计。
首先,“数字”可以是int
或int
的某些用户定义子类,或者是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