Python 为什么函数总是返回相同的类型?
我在某个地方读到函数应该总是只返回一种类型 因此,以下代码被视为坏代码:Python 为什么函数总是返回相同的类型?,python,function,return-type,Python,Function,Return Type,我在某个地方读到函数应该总是只返回一种类型 因此,以下代码被视为坏代码: def x(foo): if 'bar' in foo: return (foo, 'bar') return None 我想更好的解决办法是 def x(foo): if 'bar' in foo: return (foo, 'bar') return () 在内存方面,返回一个None,然后创建一个新的空元组不是更便宜吗?或者这个时差太小了,即使在更大的项目中也无法注意到吗?如果像这样调用x foo
def x(foo):
if 'bar' in foo:
return (foo, 'bar')
return None
我想更好的解决办法是
def x(foo):
if 'bar' in foo:
return (foo, 'bar')
return ()
在内存方面,返回一个None,然后创建一个新的空元组不是更便宜吗?或者这个时差太小了,即使在更大的项目中也无法注意到吗?如果像这样调用
x
foo, bar = x(foo)
返回None
将导致
TypeError: 'NoneType' object is not iterable
如果'bar'
不在foo
中
示例
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
这导致:
['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
['foo','bar','baz']bar
回溯(最近一次呼叫最后一次):
文件“f.py”,第9行,在
foo,bar=x([“foo”,“notthere”,“baz”])
TypeError:“非类型”对象不可编辑
为什么函数应该返回一致类型的值?要满足以下两条规则
规则1——函数有一个“类型”——输入映射到输出。它必须返回一致类型的结果,否则它不是函数。一团糟
从数学上讲,我们说某个函数F是从域D到范围R的映射。F:D->R
。域和范围构成函数的“类型”。输入类型和结果类型对于函数的定义与名称或正文一样重要
规则2——当您遇到“问题”或无法返回正确的结果时,引发异常
def x(foo):
if 'bar' in foo:
return (foo, 'bar')
raise Exception( "oh, dear me." )
您可以打破上述规则,但长期可维护性和可理解性的成本是天文数字
“返回“无”不是更便宜的内存明智吗?”错误的问题
关键不在于以清晰、可读、明显的代码为代价来优化内存。函数必须始终返回有限类型的对象,或者不返回任何对象都是错误的,这一点并不清楚。例如,re.search可以返回
\u sre.sre\u Match
对象或NoneType
对象:
import re
match=re.search('a','a')
type(match)
# <type '_sre.SRE_Match'>
match=re.search('a','b')
type(match)
# <type 'NoneType'>
如果开发人员需要重新搜索以返回\u sre.sre\u Match
对象,则
这个成语必须改成
if match.group(1) is None:
# do xyz
如果要求重新搜索始终返回\u sre.sre\u Match
对象,则不会有任何重大收益
因此,我认为如何设计函数必须取决于具体情况,尤其是计划如何使用函数
还要注意的是,\sre.sre\u Match
和NoneType
都是object的实例,因此从广义上讲,它们属于同一类型。因此,“函数应该总是只返回一种类型”的规则是毫无意义的
话虽如此,返回具有相同属性的对象的函数非常简单。(python的方式是Duck类型,而不是静态类型!)它可以让您将函数链接在一起:foo(bar(baz)),并确定您将在另一端接收的对象的类型
这可以帮助您检查代码的正确性。通过要求函数只返回某个有限类型的对象,可以减少需要检查的情况。“foo总是返回一个整数,所以只要在我使用foo的任何地方都需要一个整数,我就是黄金……”函数应该返回什么的最佳实践因语言而异,甚至在不同的Python项目之间也是如此 一般来说,对于Python,我同意这样一个前提,即如果函数通常返回iterable,则返回None是不好的,因为不进行测试就进行迭代是不可能的。只需返回一个空的iterable在这种情况下,如果使用Python的标准真理测试,它仍然会测试False:
ret_val = x()
if ret_val:
do_stuff(ret_val)
并且仍然允许您在不进行测试的情况下对其进行迭代:
for child in x():
do_other_stuff(child)
对于可能返回单个值的函数,我认为不返回任何值是完全可以接受的,只需在docstring中记录这可能发生的情况。我个人认为函数返回元组或不返回元组是完全可以接受的。但是,函数最多应返回两种不同的类型,第二种类型应为None。例如,函数不应返回字符串和列表。过早优化是万恶之源。微小的效率提升可能很重要,但除非你证明你需要它们
无论您使用何种语言:函数只定义一次,但往往用于任意数量的位置。具有一致的返回类型(更不用说记录在案的前置条件和后置条件)意味着您必须花费更多的精力定义函数,但您极大地简化了函数的使用。猜猜一次性成本是否会超过重复节省的成本…?以下是我对所有这些的看法,我还将尝试解释为什么我认为公认的答案大多是错误的 首先,
编程函数!=数学函数
。你能得到的最接近数学函数是,如果你做函数编程,但即使如此,也有大量的例子表明不是这样
- 函数不需要输入
- 函数不必有输出
- 函数不必将输入映射到输出(因为前面有两个要点)
for child in x():
do_other_stuff(child)
def foo():
pass
>> sys.getsizeof(None)
16
>> sys.getsizeof(())
48