python 从函数返回多个值的优雅方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/514038/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 20:16:31  来源:igfitidea点击:

Elegant ways to return multiple values from a function

pythonfunctionlanguage-agnosticlanguage-designsyntactic-sugar

提问by dsimcha

It seems like in most mainstream programming languages, returning multiple values from a functionis an extremely awkward thing.

似乎在大多数主流编程语言中,从一个函数返回多个值是一件非常尴尬的事情。

The typical solutions are to make either a structor a plain old data classand return that, or to pass at least some of the parameters by reference or pointer instead of returning them.

典型的解决方案是创建一个结构体或一个普通的旧数据并返回它,或者通过引用或指针传递至少一些参数而不是返回它们。

Using references/pointers is pretty awkward because it relies on side effects and means you have yet another parameter to pass.

使用引用/指针非常笨拙,因为它依赖于副作用并且意味着您还有另一个参数要传递。

The class/struct solution is also IMHO pretty awkward because you then end up with a million little classes/structs that are only used to return values from functions, generating unnecessary clutter and verbosity.

恕我直言,类/结构解决方案也很尴尬,因为您最终会得到一百万个仅用于从函数返回值的小类/结构,从而产生不必要的混乱和冗长。

Furthermore, a lot of times there's one return value that is always needed, and the rest are only used by the caller in certain circumstances. Neither of these solutions allow the caller to ignore unneeded return types.

此外,很多时候总是需要一个返回值,其余的仅在某些情况下由调用者使用。这些解决方案都不允许调用者忽略不需要的返回类型。

The one language I'm aware of that handles multiple return values elegantly is Python. For those of you who are unfamiliar, it uses tuple unpacking:

我所知道的一种可以优雅地处理多个返回值的语言是 Python。对于不熟悉的人,它使用元组解包:

a, b = foo(c)  # a and b are regular variables.
myTuple = foo(c)  # myTuple is a tuple of (a, b)

Does anyone have any other good solutions to this problem? Both idioms that work in existing mainstream languages besides Python and language-level solutions you've seen in non-mainstream languages are welcome.

有没有人有其他好的解决方案来解决这个问题?欢迎使用适用于 Python 之外的现有主流语言的习语和您在非主流语言中看到的语言级解决方案。

采纳答案by user21714

Pretty much all ML-influenced functional langues (which is most of them) also have great tuple support that makes this sort of thing trivial.

几乎所有受 ML 影响的函数式语言(其中大部分是)也有很好的元组支持,这使得这种事情变得微不足道。

For C++ I like boost::tuple plus boost::tie (or std::tr1 if you have it)

对于 C++,我喜欢 boost::tuple 加上 boost::tie(或者 std::tr1,如果你有的话)

typedef boost::tuple<double,double,double> XYZ;

XYZ foo();

double x,y,z;
boost::tie(x,y,z) = foo();

or a less contrived example

或者一个不那么做作的例子

MyMultimap::iterator lower,upper;
boost::tie(lower,upper) = some_map.equal_range(key);

回答by Moss Collum

A few languages, notably Lisp and JavaScript, have a feature called destructuring assignment or destructuring bind. This is essentially tuple unpacking on steroids: rather than being limited to sequences like tuples, lists, or generators, you can unpack more complex object structures in an assignment statement. For more details, see here for the Lisp versionor here for the (rather more readable) JavaScript version.

一些语言,特别是 Lisp 和 JavaScript,具有称为解构赋值或解构绑定的功能。这本质上是类固醇上的元组解包:您可以在赋值语句中解包更复杂的对象结构,而不是局限于像元组、列表或生成器这样的序列。有关更多详细信息,请参阅此处的 Lisp 版本此处的(更易读的)JavaScript 版本

Other than that, I don't know of many language features for dealing with multiple return values generally. However, there are a few specific uses of multiple return values that can often be replaced by other language features. For example, if one of the values is an error code, it might be better replaced with an exception.

除此之外,我不知道通常处理多个返回值的许多语言功能。但是,多返回值有一些特定用途,通常可以由其他语言功能替换。例如,如果其中一个值是错误代码,则最好将其替换为异常。

While creating new classes to hold multiple return values feels like clutter, the fact that you're returning those values together is often a sign that your code will be better overall once the class is created. In particular, other functions that deal with the same data can then move to the new class, which may make your code easier to follow. This isn't universally true, but it's worth considering. (Cpeterso's answer about data clumps expresses this in more detail).

虽然创建新类来保存多个返回值感觉很混乱,但将这些值一起返回的事实通常表明,一旦创建了类,您的代码总体上会更好。特别是,处理相同数据的其他函数然后可以移动到新类,这可能会使您的代码更容易理解。这并非普遍正确,但值得考虑。(Cpeterso 关于数据块的回答更详细地表达了这一点)。

回答by Evan Fosmark

PHP example:

PHP 示例:

function my_funct() {
    $x = "hello";
    $y = "world";
    return array($x, $y);
}

Then, when run:

然后,运行时:

list($x, $y) = my_funct();
echo $x.' '.$y; // "hello world"

回答by Chris Peterson

If a function returns multiple values, that is a sign you might be witnessing the "Data Clump" code smell. Often data clumps are primitive values that nobody thinks to turn into an object, but interesting stuff happens as you begin to look for behavior to move into the new objects.

如果函数返回多个值,则表明您可能正在目睹“Data Clump”代码异味。通常数据块是原始值,没有人认为会变成对象,但是当您开始寻找行为以移动到新对象时,有趣的事情就会发生。

Writing tiny helper classes might be extra typing, but it provides clear names and strong type checking. Developers maintaining your code will appreciate it. And useful small classes often grow up to be used in other code.

编写小助手类可能需要额外的输入,但它提供了清晰的名称和强类型检查。维护您的代码的开发人员会很感激。有用的小类通常会长大后用于其他代码。

Also, if a function returns multiple values, then it might be doing too much work. Could the function be refactored into two (or more) small functions?

此外,如果一个函数返回多个值,那么它可能做了太多工作。该函数能否重构为两个(或更多)小函数?

回答by Andru Luvisi

Nobody seems to have mentioned Perl yet.

似乎还没有人提到 Perl。

sub myfunc {
  return 1, 2;
}
my($val1, $val2) = myfunc();

回答by joel.neely

As for Java, see Bruce Eckel's Thinking in Javafor a nice solution (pp. 621 ff).

至于 Java,请参阅 Bruce Eckel 的Thinking in Java以获得一个不错的解决方案(第 621 页)。

In essence, you can define a class equivalent to the following:

本质上,您可以定义一个等效于以下内容的类:

public class Pair<T,U> {
    public final T left;
    public final U right;
    public Pair (T t, U u) { left = t; right = u; }
}

You can then use this as the return type for a function, with appropriate type parameters:

然后,您可以将其用作函数的返回类型,并带有适当的类型参数:

public Pair<String,Integer> getAnswer() {
    return new Pair<String,Integer>("the universe", 42);
}

After invoking that function:

调用该函数后:

Pair<String,Integer> myPair = getAnswer();

you can refer to myPair.leftand myPair.rightfor access to the constituent values.

您可以参考myPair.leftmyPair.right访问组成值。

There are other syntactical sugar options, but the above is the key point.

还有其他语法糖选项,但以上是关键点。

回答by SilentGhost

i thinks python's is the most natural way, when I had to do same thing in php the only was to wrap return into an array. it does have similar unpacking though.

我认为 python 是最自然的方式,当我不得不在 php 中做同样的事情时,唯一的就是将 return 包装到一个数组中。不过它确实有类似的解包。

回答by Nosredna

Even if you ignore the wonderful newer destructuring assignment Moss Collum mentioned, JavaScript is pretty nice on returning multiple results.

即使您忽略了Moss Collum 提到的美妙的新解构赋值,JavaScript 在返回多个结果方面也非常出色。

function give7and5() {
  return {x:7,y:5};
}

a=give7and5();
console.log(a.x,a.y);

7  5

回答by Norman Ramsey

Both Luaand CLU (by Barbara Liskov's group at MIT) have multiple return values for all functions---it is always the default. I believe the designers of Lua were inspired by CLU. I like having multiple values be the default for calls and returns; I think it is a very elegant way of thinking about things. In Lua and CLU this mechanism is completely independent of tuples and/or records.

双方的Lua和CLU(芭芭拉里氏公司在麻省理工学院组)对所有功能的多个返回值---它始终是默认。我相信 Lua 的设计者受到了 CLU 的启发。我喜欢将多个值作为调用和返回的默认值;我认为这是一种非常优雅的思考方式。在 Lua 和 CLU 中,这种机制完全独立于元组和/或记录。

The portable assembly language C--supports multiple return values for its native calling convention but not for the C calling convention. There the idea is to enable a compiler writer to return multiple values in individual hardware registers rather than having to put the values in a clump in memory and return a pointer to that clump (or as in C, have the caller pass a pointer to an empty clump).

可移植汇编语言C--支持其本地调用约定的多个返回值,但不支持 C 调用约定。这里的想法是让编译器编写者能够在单个硬件寄存器中返回多个值,而不必将这些值放在内存中的一个块中并返回一个指向该块的指针(或者像在 C 中一样,让调用者将一个指针传递给一个空团)。

Like any mechanism, multiple return values can be abused, but I don't think it is any more unreasonable to have a function return multiple values than it is to have a struct contain multiple values.

像任何机制一样,可以滥用多个返回值,但我认为让函数返回多个值并不比让结构包含多个值更不合理。

回答by willoller

Often in php I'll use a referenced input:

通常在 php 中,我会使用引用的输入:

public function Validates(&$errors=array()) {
   if($failstest) {
      $errors[] = "It failed";
      return false;
   } else {
      return true;
   }
}

That gives me the error messages I want without polluting the bool return, so I can still do:

这给了我我想要的错误消息而不会污染 bool 返回,所以我仍然可以这样做:

if($this->Validates()) ...