请帮助我的团队解决这个争论:
如果我们有一个函数可以获取一个点(3个值的列表)或一个点列表,那么我们有:
Argumente = []
'bytearray([source[, encoding[, errors]]])'
.replace(/\[[, ]*(\w+)|(\w+)(?=[[,)])/g,
function(m, p1, p2)
{
Argumente.push({ name: p1||p2, optional: !p2 })
})
console.log(Argumente)
或
def f(point=None, points=None):
if points is None: points = []
if point is not None: points.append(point)
.... stuff with "points" ....
被称为,
def g(points):
if len(points) > 0 and not isinstance(points[0],list):
points = [points]
.... stuff with "points" ....
其中x,y,z和w应该都是相同的(如果f和g是相同的函数)。
也就是说,x = f(points=[[1,2,3],[4,5,6]])
y = f(point=[1,2,3])
z = g(points=[[1,2,3],[4,5,6]])
w = g(points=[1,2,3])
和f
内部都需要一个二维数组,但提供接受一维数组的机制。
不同之处在于g
每个类型都有一个参数,因此每个参数都需要一个特定的类型,但f
只有一个参数,可能有多种类型。
问题是,哪种风格更多" Pythonic"? (参考PEP更受欢迎......我无法找到任何东西。)
编辑:我忘了提到表面上支持1维输入的原因是向后兼容性。也就是说,g
已经存在,我们正在将其更改为f(point, axis)
..我们正在尝试更改调用者,因为它们位于此代码库的外部。我同意也许正确的答案是不这样做并迫使调用者与他们的类型保持一致,但我要求读者认为这将是困难的,并提供一些明确的我要问的两个选择,如果可能的话。谢谢!
答案 0 :(得分:2)
由于f
和g
的签名不同,我假设您控制了函数的调用方式。在这种情况下,最合乎逻辑的做法是只接受二维列表并将其称为:
x = h([[1,2,3], [4,5,6]])
y = h([[1,2,3]])
只有一个元素的点列表不是特例,除非它在语义上与上下文中的多点列表不同,否则会改变函数行为。
答案 1 :(得分:1)
我建议使用* args (或者,好吧,可能称之为*点)并让用户解开他的点数。
这允许您拨打 f(点), f(点1,点2,点3)或 f(* list_of_points),所有三个选项都正常工作,你可以做到:
def f(*points):
...
for point in points:
do_pointy_stuff(point)
...类似于g2但没有hacky isinstance 检查如果有人决定投入元组或其他东西会失败。
然而,这里存在一个小的潜在缺陷 - 用户必须故意解开他的积分列表。如果你在使用单个参数时没有注意,你可以传递* [points]而不是* [[list of points]],这会导致函数将每个坐标视为一个单独的参数本身和大多数可能会抛出错误。