假设我想要一个采用list
的简单方法,并通过向其添加5
来就地修改它。以下是执行此操作的两种方法,但ret(l)
会返回,而no_ret(l)
则不会。
def ret(l):
l.append(5)
return l
def no_ret(l):
l.append(5)
哪种方法更pythonic?我猜no_ret()
因为如果方法是用于就地修改,那么就没有必要返回,因为我们已经有了对被修改对象的引用。
他们如何在时间和空间效率方面进行比较?
ret(l)
较慢,因为return语句会增加额外的开销。ret()
只返回一个引用(内存地址),所以没有使用新的内存。我注意到Python提供了就地非返回实例方法sort()
和非就地返回静态方法sorted()
。但是,我不能使我的就地方法成为像list
这样的默认类的实例方法。
答案 0 :(得分:2)
您不应该做的第一件事是使用您自己的方法复制现有功能 - 但是,我假设您只是给出一个示例,而这不是您计划运行的实际代码。
Python中的所有方法都返回一个值。如果方法没有return语句,则返回None
。
任何就地修改但不返回的函数;不应该返回一个值。这是有道理的,因为它是“正常”就地方法的工作方式。
正确的实施方式是:
def do_something(foo, bar):
foo.do_something_inplace(bar)
return None # or simply, return
空白返回与return None
相同,但请记住 - 显式优于隐式。
关于空间和时间效率的另一个问题,这完全取决于实际进行替换的方法的实现。在您的示例中编写内置方法的代理时,“速度惩罚”可以忽略不计。
答案 1 :(得分:0)
在评估 pythonic 某些代码的方式时,我们应该查看标准库。两个可变对象是:
list
使用就地方法append
:
mylist = [1,2,3]
mylist.append(5).append(3) # Throws error 'NoneType' object has no attribute 'append'
dict
使用就地方法update
:
mydict={}
mydict.update(mydict).update(mydict) # Throws error 'NoneType' object has no attribute 'update'
我们可以得出结论,就地方法应该返回None
性能考虑因素:
<强> test.py 强>
def ret(l):
l.append(5)
return l
def no_ret(l):
l.append(5)
def test_ret():
l=[]
for i in xrange(100000):
ret(l)
def test_no_ret():
l=[]
for i in xrange(100000):
no_ret(l)
在%timeit
的IPython中:
In [3]: %timeit test_ret()
10 loops, best of 3: 163 ms per loop
In [4]: %timeit test_no_ret()
10 loops, best of 3: 161 ms per loop
非返回方法不比在C-Python中返回更快。
编辑发表评论
你可以在python中使任何方法成为类的实例方法:
class MyObject(object):
def __init__(self):
self.l=[]
def ret(self):
self.l.append(randint(10,15))
return self
IPython的:
In [3]: setattr(MyObject,"ret", ret)
In [4]: MyObject().ret()
Out[4]: <test.MyObject at 0x7f6428e8ccd0>
In [5]: MyObject().ret().l
Out[5]: [15]