python 为什么函数应该总是返回相同的类型?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1839289/
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
Why should functions always return the same type?
提问by self.self
I read somewhere that functions should always return only one type so the following code is considered as bad code:
我在某处读到函数应该始终只返回一种类型,因此以下代码被视为错误代码:
def x(foo):
if 'bar' in foo:
return (foo, 'bar')
return None
I guess the better solution would be
我想更好的解决方案是
def x(foo):
if 'bar' in foo:
return (foo, 'bar')
return ()
Wouldn't it be cheaper memory wise to return a None then to create a new empty tuple or is this time difference too small to notice even in larger projects?
返回一个 None 然后创建一个新的空元组不是更便宜的内存明智的,还是这个时间差太小以至于即使在更大的项目中也无法注意到?
回答by S.Lott
Why should functions return values of a consistent type? To meet the following two rules.
为什么函数应该返回一致类型的值?满足以下两条规则。
Rule 1 -- a function has a "type" -- inputs mapped to outputs. It must return a consistent type of result, or it isn't a function. It's a mess.
规则 1——一个函数有一个“类型”——输入映射到输出。它必须返回一致类型的结果,否则它不是一个函数。一团糟。
Mathematically, we say some function, F, is a mapping from domain, D, to range, R. F: D -> R
. The domain and range form the "type" of the function. The input types and the result type are as essential to the definition of the function as is the name or the body.
在数学上,我们说某个函数 F 是从域 D 到范围 R 的映射 F: D -> R
。域和范围构成了函数的“类型”。输入类型和结果类型对于函数的定义与名称或函数体一样重要。
Rule 2 -- when you have a "problem" or can't return a proper result, raise an exception.
规则 2——当您遇到“问题”或无法返回正确结果时,引发异常。
def x(foo):
if 'bar' in foo:
return (foo, 'bar')
raise Exception( "oh, dear me." )
You canbreak the above rules, but the cost of long-term maintainability and comprehensibility is astronomical.
你可以打破上述规则,但长期可维护性和可理解性的代价是天文数字。
"Wouldn't it be cheaper memory wise to return a None?" Wrong question.
“返回 None 不是更便宜的内存明智吗?” 错误的问题。
The point is notto optimize memory at the cost of clear, readable, obvious code.
重点不是以清晰、可读、明显的代码为代价来优化内存。
回答by unutbu
It's not so clear that a function must always return objects of a limited type, or that returning None is wrong. For instance, re.search can return a _sre.SRE_Match
object or a NoneType
object:
函数必须始终返回有限类型的对象,或者返回 None 是错误的,这一点并不是很清楚。例如,re.search 可以返回一个_sre.SRE_Match
对象或一个NoneType
对象:
import re
match=re.search('a','a')
type(match)
# <type '_sre.SRE_Match'>
match=re.search('a','b')
type(match)
# <type 'NoneType'>
Designed this way, you can test for a match with the idiom
这样设计,你可以测试是否与成语匹配
if match:
# do xyz
If the developers had required re.search to return a _sre.SRE_Match
object, then
the idiom would have to change to
如果开发人员要求 re.search 返回一个_sre.SRE_Match
对象,那么习惯用法必须更改为
if match.group(1) is None:
# do xyz
There would not be any major gain by requiring re.search to always return a _sre.SRE_Match
object.
要求 re.search 始终返回一个_sre.SRE_Match
对象不会有任何重大好处。
So I think how you design the function must depend on the situation and in particular, how you plan to use the function.
所以我认为你如何设计这个功能必须取决于情况,特别是你打算如何使用这个功能。
Also note that both _sre.SRE_Match
and NoneType
are instances of object, so in a broad sense they are of the same type. So the rule that "functions should always return only one type" is rather meaningless.
另请注意,_sre.SRE_Match
和NoneType
都是 object 的实例,因此从广义上讲,它们属于同一类型。所以“函数应该总是只返回一种类型”的规则是毫无意义的。
Having said that, there is a beautiful simplicity to functions that return objects which all share the same properties. (Duck typing, not static typing, is the python way!) It can allow you to chain together functions: foo(bar(baz))) and know with certainty the type of object you'll receive at the other end.
话虽如此,返回共享相同属性的对象的函数非常简单。(鸭子类型,而不是静态类型,是 Python 方式!)它可以让您将函数链接在一起:foo(bar(baz))) 并确定地知道您将在另一端收到的对象类型。
This can help you check the correctness of your code. By requiring that a function returns only objects of a certain limited type, there are fewer cases to check. "foo always returns an integer, so as long as an integer is expected everywhere I use foo, I'm golden..."
这可以帮助您检查代码的正确性。通过要求函数只返回特定有限类型的对象,需要检查的情况就更少了。“foo 总是返回一个整数,所以只要在我使用 foo 的任何地方都需要一个整数,我就是金子……”
回答by Jeffrey Harris
Best practice in what a function should return varies greatly from language to language, and even between different Python projects.
函数应该返回什么的最佳实践因语言而异,甚至在不同的 Python 项目之间也是如此。
For Python in general, I agree with the premise that returning None is bad if your function generally returns an iterable, because iterating without testing becomes impossible. Just return an empty iterable in this case, it will still test False if you use Python's standard truth testing:
一般来说,对于 Python,我同意这样一个前提,即如果您的函数通常返回一个可迭代对象,则返回 None 是不好的,因为没有测试的迭代变得不可能。在这种情况下只返回一个空的可迭代对象,如果您使用 Python 的标准真值测试,它仍然会测试 False:
ret_val = x()
if ret_val:
do_stuff(ret_val)
and still allow you to iterate over it without testing:
并且仍然允许您在不测试的情况下对其进行迭代:
for child in x():
do_other_stuff(child)
For functions that are likely to return a single value, I think returning None is perfectly acceptable, just document that this might happen in your docstring.
对于可能返回单个值的函数,我认为返回 None 是完全可以接受的,只需记录这可能会在您的文档字符串中发生。
回答by rbaleksandar
Here are my thoughts on all that and I'll try to also explain why I think that the accepted answer is mostly incorrect.
这是我对所有这些的想法,我还将尝试解释为什么我认为已接受的答案大多是不正确的。
First of all programming functions != mathematical functions
. The closest you can get to mathematical functions is if you do functional programming but even then there are plenty of examples that say otherwise.
首先programming functions != mathematical functions
。最接近数学函数的是,如果您进行函数式编程,但即便如此,仍有大量示例表明情况并非如此。
- Functions do nothave to have input
- Functions do nothave to have output
- Functions do nothave to map input to output (because of the previous two bullet points)
- 函数不必有输入
- 函数不一定要有输出
- 函数不必将输入映射到输出(因为前两个要点)
A function in terms of programming is to be viewed simply as a block of memory with a start (the function's entry point), a body (empty or otherwise) and exit point (one or multiple depending on the implementation) all of which are there for the purpose of reusing code that you've written. Even if you don't see it a function always "returns" something. This something is actually the address of next statement right after the function call. This is something you will see in all of its glory if you do some really low-level programming with an Assembly language (I dare you to go the extra mile and do some machine code by hand like Linus Torvalds who ever so often mentions this during his seminars and interviews :D). In addition you can also take some input and also spit out some output. That is why
就编程而言,函数可以简单地视为具有开始(函数的入口点)、主体(空或其他)和出口点(一个或多个,取决于实现)的内存块,所有这些都在那里为了重用您编写的代码。即使你没有看到它,一个函数也总是“返回”一些东西。这东西实际上是函数调用之后的下一条语句的地址。如果您使用汇编语言进行一些真正的低级编程,那么您将看到它的所有荣耀(我敢于您多走一步并像 Linus Torvalds 一样手工编写一些机器代码,他在他的研讨会和采访:D)。此外,您还可以获取一些输入并吐出一些输出。因此
def foo():
pass
is a perfectly correct piece of code.
是一段完全正确的代码。
So why would returning multiple types be bad? Well...It isn't at all unless you abuse it. This is of course a matter of poor programming skills and/or not knowing what the language you're using can do.
那么为什么返回多个类型会很糟糕呢?嗯......它根本不是,除非你滥用它。这当然是编程技能不佳和/或不知道您使用的语言可以做什么的问题。
Wouldn't it be cheaper memory wise to return a None then to create a new empty tuple or is this time difference too small to notice even in larger projects?
返回一个 None 然后创建一个新的空元组不是更便宜的内存明智的,还是这个时间差太小以至于即使在更大的项目中也无法注意到?
As far as I know - yes, returning a NoneType
object would be much cheaper memory-wise. Here is a small experiment (returned values are bytes):
据我所知 - 是的,返回一个NoneType
对象在内存方面会便宜得多。这是一个小实验(返回值是字节):
>> sys.getsizeof(None)
16
>> sys.getsizeof(())
48
Based on the type of object you are using as your return value (numeric type, list, dictionary, tuple etc.) Python manages the memory in different ways including the initially reserved storage.
根据您用作返回值的对象类型(数字类型、列表、字典、元组等),Python 以不同的方式管理内存,包括最初保留的存储。
However you have to also consider the code that is around the function call and how it handles whatever your function returns. Do you check for NoneType
? Or do you simply check if the returned tuple has length of 0? This propagation of the returned value and its type (NoneType
vs. empty tuple in your case) might actually be more tedious to handle and blow up in your face. Don't forget - the code itself is loaded into memory so if handling the NoneType
requires too much code (even small pieces of code but in a large quantity) better leave the empty tuple, which will also avoid confusion in the minds of people using your function and forgetting that it actually returns 2 types of values.
但是,您还必须考虑函数调用周围的代码以及它如何处理您的函数返回的任何内容。你检查NoneType
吗?或者你只是检查返回的元组的长度是否为 0?返回值及其类型的这种传播(NoneType
与您的情况下的空元组相比)实际上可能更乏味处理并在您面前炸毁。不要忘记 - 代码本身已加载到内存中,因此如果处理NoneType
需要太多代码(即使是少量代码但数量很大),最好保留空元组,这也将避免使用您的人的头脑中的混乱函数而忘记它实际上返回 2 种类型的值。
Speaking of returning multiple types of value this is the part where I agree with the accepted answer (but only partially) - returning a single type makes the code more maintainable without a doubt. It's much easier to check only for type A then A, B, C, ... etc.
说到返回多种类型的值,这是我同意接受的答案的部分(但只是部分)——毫无疑问,返回单一类型会使代码更易于维护。仅检查类型 A 然后检查 A、B、C 等要容易得多。
However Python is an object-oriented language and as such inheritance, abstract classes etc. and all that is part of the whole OOP shenanigans comes into play. It can go as far as even generating classes on-the-fly, which I have discovered a few months ago and was stunned (never seen that stuff in C/C++).
然而,Python 是一种面向对象的语言,因此继承、抽象类等以及作为整个 OOP 恶作剧一部分的所有内容都会发挥作用。它甚至可以即时生成类,我在几个月前发现了这一点并惊呆了(从未在 C/C++ 中看到过这种东西)。
Side note:You can read a little bit about metaclasses and dynamic classes in this nice overview articlewith plenty of examples.
旁注:您可以在这篇带有大量示例的精彩概述文章中阅读有关元类和动态类的一些内容。
There are in fact multiple design patterns and techniques that wouldn't even exists without the so called polymorphic functions. Below I give you two very popular topics (can't find a better way to summarize both in a single term):
事实上,如果没有所谓的多态函数,甚至不存在多种设计模式和技术。下面我给你两个非常受欢迎的话题(找不到更好的方法来概括这两个词):
- Duck typing- often part of the dynamic typing languages which Python is a representative of
- Factorymethod design pattern - basically it's a function that returns various objects based on the input it receives.
Finally whether your function returns one or multiple types is totally based on the problem you have to solve. Can this polymorphic behaviour be abused? Sure, like everything else.
最后,您的函数是否返回一种或多种类型完全取决于您必须解决的问题。这种多态行为可以被滥用吗?当然,就像其他一切一样。
回答by Echo says Reinstate Monica
I personally think it is perfectly fine for a function to return a tuple or None. However, a function should return at most 2 different types and the second one should be a None. A function should never return a string and list for example.
我个人认为函数返回元组或 None 是完全没问题的。但是,一个函数最多应该返回 2 种不同的类型,第二个应该是 None。例如,函数不应返回字符串和列表。
回答by Echo says Reinstate Monica
If x
is called like this
如果这样x
调用
foo, bar = x(foo)
returning None
would result in a
返回None
将导致
TypeError: 'NoneType' object is not iterable
if 'bar'
is not in foo
.
如果'bar'
不在foo
.
Example
例子
def x(foo):
if 'bar' in foo:
return (foo, 'bar')
return None
foo, bar = x(["foo", "bar", "baz"])
print foo, bar
foo, bar = x(["foo", "NOT THERE", "baz"])
print foo, bar
This results in:
这导致:
['foo', 'bar', 'baz'] bar
Traceback (most recent call last):
File "f.py", line 9, in <module>
foo, bar = x(["foo", "NOT THERE", "baz"])
TypeError: 'NoneType' object is not iterable
回答by Pontus Gagge
Premature optimization is the root of all evil. The minuscule efficiency gains might be important, but not until you've proven that you need them.
过早的优化是万恶之源。微小的效率提升可能很重要,但除非您证明自己需要它们。
Whatever your language: a function is defined once, but tends to be used at any number of places. Having a consistent return type (not to mention documented pre- and postconditions) means you have to spend more effort definingthe function, but you simplify the usageof the function enormously. Guess whether the one-time costs tend to outweigh the repeated savings...?
无论您使用何种语言:一个函数被定义一次,但往往会在任意数量的地方使用。具有一致的返回类型(更不用说记录的前置和后置条件)意味着您必须花费更多精力定义函数,但是您极大地简化了函数的使用。猜猜一次性成本是否会超过重复节省的成本……?