Appending to range function

故事扮演 提交于 2019-12-17 17:04:45

问题


EDIT: Thank you for your kind replies on how to accomplish what I am trying to do, but the question is about WHY range().append() returns None if you try it in one step, and WHY it works if you two-step the procedure.

Im trying to create a numerical list but with a twist. I don't want a couple of numbers at the beggining of my list:

mlist = [0, 5, 6, 7, ...]

So i thought to do the following:

 mlist = range(5,n+1).append(0)

but silently fails because type(mlist) afterwards equals to NoneType ?! (related: type(range(5,10) evaluates to list Type)

If i try to do that in two steps eg:

>>> mlist = range(5,10)
#and then
>>> mlist.append(0)
>>> mlist
[5, 6, 7, 8, 9, 10, 0]

What's happening?


回答1:


list.append() alters the list in place, and returns None. By assigning you assigned that return value to mlist, not the list you wanted to build. This is a standard Python idiom; methods that alter the mutable object never return the altered object, always None.

Separate the two steps:

mlist = range(5, n + 1)
mlist.append(0)

This adds [0] to the end; if you need the 0 at the start, use:

mlist = [0] + range(5, n + 1)

or you can use list.insert(), again as a separate call:

mlist = range(5, n + 1)
mlist.insert(0, 0)

but the latter has to shift up all elements one step and creating a new list by concatenation is the faster option for shorter lists, insertion wins on longer lists:

>>> from timeit import timeit
>>> def concat(n):
...     mlist = [0] + range(5, n)
... 
>>> def insert(n):
...     mlist = range(5, n)
...     mlist.insert(0, 0)
... 
>>> timeit('concat(10)', 'from __main__ import concat')
1.2668070793151855
>>> timeit('insert(10)', 'from __main__ import insert')
1.4820878505706787
>>> timeit('concat(1000)', 'from __main__ import concat')
23.53221583366394
>>> timeit('insert(1000)', 'from __main__ import insert')
15.84601092338562



回答2:


There are multiple options, but the simplest one might be:

>>> mlist = [0] + range(5,10)
>>> mlist
[0, 5, 6, 7, 8, 9]

To insert an item at the beginning, use list.insert with 0 (index 0):

>>> mlist = range(5,10)
>>> mlist.insert(0, 0) # the first 0: index, the second 0: the item to insert
>>> mlist
[0, 5, 6, 7, 8, 9]

Answer to EDIT:

Most methods that change the sequence/maping in place return None. So just call the method, and do not reassign the return value to the variable.

See Why doesn’t list.sort() return the sorted list? from the Python FAQ.




回答3:


EDIT: Thank you for your kind replies on how to accomplish what I am trying to do, but the question is about WHY range().append() returns None if you try it in one step, and WHY it works if you two-step the procedure.

Put simply - GvR didn't like it - from the Python developers mailing list:

I'd like to explain once more why I'm so adamant that sort() shouldn't return 'self'.

This comes from a coding style (popular in various other languages, I believe especially Lisp revels in it) where a series of side effects on a single object can be chained like this:

x.compress().chop(y).sort(z)

which would be the same as

x.compress()
x.chop(y)
x.sort(z)

I find the chaining form a threat to readability; it requires that the reader must be intimately familiar with each of the methods. The second form makes it clear that each of these calls acts on the same object, and so even if you don't know the class and its methods very well, you can understand that the second and third call are applied to x (and that all calls are made for their side-effects), and not to something else.

I'd like to reserve chaining for operations that return new values, like string processing operations:

y = x.rstrip("\n").split(":").lower()

There are a few standard library modules that encourage chaining of side-effect calls (pstat comes to mind). There shouldn't be any new ones; pstat slipped through my filter when it was weak.



来源:https://stackoverflow.com/questions/20018758/appending-to-range-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!