Списъкът на Python разширява функционалността чрез срезове

Уча се на Python, преди да започна нова работа. Това е работа на Django, така че трябва да се придържам към 2.7. Като такъв, чета Начало на Python от Hetland и не разбират неговия пример за използване на срезове за възпроизвеждане на list.extend() функционалност.

Първо, той показва метода extend от

a = [1, 2, 3]
b = [4, 5, 6]
a.extend(b)

произвежда [1, 2, 3, 4, 5, 6]

След това той демонстрира разширяване чрез нарязване на via

a = [1, 2, 3]
b = [4, 5, 6]
a[len(a):] = b

което произвежда точно същия резултат като първия пример.

Как работи това? A има дължина 3 и крайната индексна точка на среза е празна, което означава, че се изпълнява до края на списъка. Как стойностите b се добавят към a?


person Jason    schedule 18.05.2013    source източник


Отговори (4)


Синтаксисът за присвояване на срезове на Python означава „направете този срез равен на тази стойност, разширявайки или свивайки списъка, ако е необходимо“. За да го разберете напълно, може да искате да изпробвате някои други стойности на срезове:

a = [1, 2, 3]
b = [4, 5, 6]

Първо, нека заменим част от A с B:

a[1:2] = b
print(a) # prints [1, 4, 5, 6, 3]

Вместо да замените някои стойности, можете да ги добавите, като присвоите на срез с нулева дължина:

a[1:1] = b
print(a) # prints [1, 4, 5, 6, 2, 3]

Всеки срез, който е „извън границите“, вместо това просто адресира празна област в единия или другия край на списъка (твърде големите положителни числа ще адресират точката точно до края, докато твърде големите отрицателни числа ще адресират точката точно преди началото ):

a[200:300] = b
print(a) # prints [1, 2, 3, 4, 5, 6]

Вашият примерен код просто използва най-"точния" срез извън границите в края на списъка. Не мисля, че това е код, който бихте използвали съзнателно за разширяване, но може да е полезен като краен случай, който не е необходимо да обработвате със специална логика.

person Blckknght    schedule 18.05.2013

Това е просто разширение на нормалното индексиране.

>>> L
[1, 2, 3, 4, 5]
>>> L[2] = 42
>>> L
[1, 2, 42, 4, 5]

Методът __setitem__() открива, че се използва срез вместо нормален индекс и се държи правилно.

person Ignacio Vazquez-Abrams    schedule 18.05.2013
comment
Не мисля, че това е много полезно. L[len(L)] = 6 не е законно, но еквивалентът на срез L[len(L):] = [6] е. - person Blckknght; 18.05.2013
comment
@Blckknght: Срезовете никога не са извън границите. L = []; L[123456:] не е проблем. - person Martijn Pieters; 18.05.2013
comment
@Blckknght: Те също предават напълно различни типове като индекс на метода. - person Ignacio Vazquez-Abrams; 18.05.2013
comment
В моя пример създава ли нов списък, съпоставен с променлива a? - person Jason; 18.05.2013
comment
@Джейсън: Не, тъй като заданията на срезове в списък променят съществуващия списък. - person Ignacio Vazquez-Abrams; 18.05.2013
comment
@IgnacioVazquez-Abrams, в Java ArrayList се адаптира към добавяне на нов елемент след текущата му индексна точка, като създава ново поле за масив с удвоен брой индекси, копира над съществуващите елементи, след което накрая вмъква новия елемент. Това подобно ли е на начина, по който присвояванията на срезове променят съществуващия списък? - person Jason; 18.05.2013
comment
@Jason: Присвояванията на срезове не увеличават непременно размера на списъка, но ако го направят, процесът (в CPython) е подобен. - person Ignacio Vazquez-Abrams; 18.05.2013
comment
@IgnacioVazquez-Abrams: Да, различният тип, предаден на __setitem__, е начинът, по който Python открива присвояването на срезове вътрешно. Но мисля, че въпросът е какво означава присвояването, когато се работи с резени. Отговорът ви не казва нищо друго освен това, че се държи правилно, което не изглежда полезно, освен ако вече не знаете цялата логика за присвояване на срезове. Вашият пример за присвояване на елемент без срез е просто червена херинга. - person Blckknght; 18.05.2013

a = [1, 2, 3]
b = [4, 5, 6]
a[len(a):] = b

означава елемент в a от позиция len(a) са елементи в b. Което означава разширяване на a с b.

person kiriloff    schedule 18.05.2013

За демонстрация помислете за разглеждане на подклас на list:

from __future__ import print_function     # so I can run on Py 3 and Py 2

class EdList(list):
    def __setitem__(self,index,value):
        print('setitem: index={}, value={}'.format(index,value))
        list.__setitem__(self,index,value)    
        print(self)

    def __setslice__(self,i,j,seq):
        print('setslice: i:{}, j:{}, seq:{}'.format(i,j,seq))
        self.__setitem__(slice(i,j),seq)

Работи на Python 3:

>>> a=EdList(range(10))
>>> a[300000:]=[1,2,3]
setitem: index=slice(300000, None, None), value=[1, 2, 3]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3]
>>> a[1:1]=[4,5,6]
setitem: index=slice(1, 1, None), value=[4, 5, 6]
[0, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3]

Работи на Python 2:

>>> a=EdList(range(10))
>>> a[300000:]=[1,2,3]
setslice: i:300000, j:9223372036854775807, seq:[1, 2, 3]
setitem: index=slice(300000, 9223372036854775807, None), value=[1, 2, 3]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3]
>>> a[1:1]=[4,5,6]
setslice: i:1, j:1, seq:[4, 5, 6]
setitem: index=slice(1, 1, None), value=[4, 5, 6]
[0, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3]

Объркващо е, когато го изучавате за първи път, но мисля, че ще се научите да го обичате.

person dawg    schedule 22.05.2013