根据传入参数的数量改变返回值的数量

3
有没有一种简便的方法来处理参数元组*args,如果函数只接收到一个参数,则返回单个参数,否则返回参数元组?就像下面的例子一样。
def transform(*args):
    if len(args) == 1:
        return args[0] + 1
    else:
        return tuple(arg + 1 for arg in args)
这样,对于单个参数,您可以直接调用 transform 而无需进行额外的解包:
x = transform(3)

同时也适用于多个参数:

a, b, c = transform(1, 2, 3)
另一个选择是始终采用 Sized 并返回 Sized。
def transform_2(args):
    return tuple(arg + 1 for arg in args)

但这似乎会使用户代码变得不太直观:

x, = transform_2((3,))
a, b, c = transform_2((1, 2, 3))

还是这个解决方案更好?


1
你不应该这样做。这违反了单一返回类型规则。https://dev59.com/LXI-5IYBdhLWcg3weoJO - FHTMitchell
不完全是这样。如果你的输入是一个元组,那么它应该写成 transform((1, 2, 3))。在正式类型系统中,(Int) -> T1(Int, Int?, Int?) -> T2 的超类型,因此 T2 必须是 T1 的子类型(这里我使用 ? 表示可选,而不是 Kotlin 中的可为空)。我同意,像 (T) -> T 这样的函数是可以接受的。 - FHTMitchell
即使一个类型为(T) -> T的函数并不是一个单一函数;它是一个整个函数类的模式,例如(Int) -> Int(Char) -> Char等等。 - chepner
@chepner 是的,但关键是它不会破坏类型系统。C# 对 static T Method<T>(T arg) (我认为)非常满意。 - FHTMitchell
@jpp,你能否重新打开这个问题 - 我已经根据讨论进行了更改,现在我可以正确地回答它。 - DikobrAz
显示剩余2条评论
1个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
2

一个总是使用可迭代对象的API更易于理解,对用户的负担也不是很大。

def transform(args):
    return tuple(arg + 1 for arg in args)

x = transform((3,))  # or transform([3])
a, b, c = transform([1,2,3])

如果您试图传递一个字符串,那么任何尝试做您正在尝试的事情的尝试都会失败,因为您可能希望foo("123")返回单个值,而不是foo("1")foo("2")foo("3")的结果,但除非明确测试str,否则您将无法区分字符串参数和其他可迭代对象。


请问您能否澄清一下?为什么它更加用户友好并不明显。 - DikobrAz
1
@asynts 这个问题的前提是错误的。 - chepner
在我提供的例子中,transform("123") 实际上做到了预期的效果 - 转换 "123",而不是转换 "1"、"2" 和 "3"。 - DikobrAz
@DikobrAz 是的,你的函数比一个简单地修改可迭代对象中每个元素并将其留给调用者提供可迭代对象的函数更加复杂和难以测试和维护。 - chepner
@chepner 我同意这种方法更难维护,这也是我提出这个问题的原因,想看看是否有更好的解决方案。但用户需要编写的代码更少,而且看起来非常直观。此外,它似乎更不容易出错,在你的例子中,如果用户意外调用了 transform("123") 而不是 transform(("123",)),那么他将得到 transform("1"), transform("2"), transform("3"),这是不期望的,而我也无法检查这种情况并引发错误。 - DikobrAz
问题:用户不知道字符串是可迭代的。解决方案:用户学习字符串是可迭代的。问题解决了。如果您愿意,可以提供两个分别为 transformtransform_all 的函数。但不要试图创建一个既能满足所有人又能胜任一切的单一函数。 - chepner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,