일반인을 위한 파이썬 지침서/리스트를 더 자세히
우리는 이미 리스트가 어떻게 사용될 수 있는지 살펴본 바 있다. 이제 여러분은 좀더 배경지식을 같게 되었으므로 나는 리스트에 대하여 좀 더 자세하게 들어가 보려고 한다. 먼저 리스트에서 요소를 획득하는 더 많은 방법을 살펴볼 것이다. 그리고 우리는 그것들을 복사하는 것에 대하여 논의할 것이다.
여기에 지표를 사용하여 리스트의 구성요소에 접근하는 약간의 예제가 있다.
>>> list = ['zero','one','two','three','four','five'] >>> list[0] 'zero' >>> list[4] 'four' >>> list[5] 'five'
이러한 모든 예제들은 여러분에게 매우 친숙하게 보여야만 한다. 여러분이 리스트에서 첫 번째 항목을 원한다면 단지 지표 0을 살펴보라. 두 번째 항목은 지표 1 이고 그런식으로 리스트의 마지막까지 간다. 그렇지만 여러분이 리스트의 마지막 항목을 원한다면 어떻게 할까? 하나의 방법은 'list[len(list)-1]'와 같이 len 함수를 사용하는 것이다. len함수가 항상 마지막 지표 더하기 1 값을 반환해 주므로 이것은 잘 작동한다. 마지막으로부터 두 번째는 그러면 list[len(list)-2] 이 될 것이다. 이것을 위한 더 쉬운 방법이 있다. 파이썬에서 가장 마지막 항목은 항상 'index-1' 이다. 마지막에서 두번째는 'index -2' 이다. 등등. 여기에 예제를 더 보인다면 다음과 같다.
>>> list[len(list)-1] 'five' >>> list[len(list)-2] 'four' >>> list[-1] 'five' >>> list[-2] 'four' >>> list[-6] 'zero'
이렇게 리스트의 어떤 항목도 두 가지 방법으로 지표화 될 수 있다. 앞으로 부터 그리고 뒤로 부터
리스트의 부분으로 들어가는 또 다른 유용한 방법은 썰기이다. 여기에 여러분에게 썰기가 무엇에 유용한지 아이디어를 제공하는 또 다른 예제가 있다.
>>> list = [0,'Fred',2,'S.P.A.M.','Stocking',42,"Jack","Jill"] >>> list[0] 0 >>> list[7] 'Jill' >>> list[0:8] [0, 'Fred', 2, 'S.P.A.M.', 'Stocking', 42, 'Jack', 'Jill'] >>> list[2:4] [2, 'S.P.A.M.'] >>> list[4:7] ['Stocking', 42, 'Jack'] >>> list[1:5] ['Fred', 2, 'S.P.A.M.', 'Stocking']
썰기는 리스트의 부분을 반환하는데 사용된다. 썰기 연산자는 list[first_index:following_index]의 형태로 사용된다. 썰기는 first_index로부터 following_index앞의 지표까지 실행된다. 여러분은 지표화 형태 두 가지 모두를 사용할 수 있다.
>>> list[-4:-2] ['Stocking', 42] >>> list[-4] 'Stocking' >>> list[-4:6] ['Stocking', 42]
썰기에 대한 또 다른 꼼수는 지표를 생략하는 것이다. 만약 첫 번째 지표가 생략되면 리스트의 처음이라고 가정된다. 만약 다음의 지표가 생략되면 그 리스트의 나머지 전체라고 가정된다. 여기에 약간의 예제가 있다.
>>> list[:2] [0, 'Fred'] >>> list[-2:] ['Jack', 'Jill'] >>> list[:3] [0, 'Fred', 2] >>> list[:-5] [0, 'Fred', 2]
여기에 하나의 프로그램 예제가 있다.(여러분이 원한다면 시를 정의하는 형태로 복사하고 붙여넣어라.)
poem = ["<B>","Jack","and","Jill","</B>","went","up","the","hill","to","<B>",\ "fetch","a","pail","of","</B>","water.","Jack","fell","<B>","down","and",\ "broke","</B>","his","crown","and","<B>","Jill","came","</B>","tumbling",\ "after"] def get_bolds(list): true = 1 false = 0 ## is_bold tells whether or not the we are currently looking at ## a bold section of text. is_bold = false ## start_block is the index of the start of either an unbolded ## segment of text or a bolded segment. start_block = 0 for index in range(len(list)): ##Handle a starting of bold text if list[index] == "<B>": if is_bold: print "Error: Extra Bold" ##print "Not Bold:",list[start_block:index] is_bold = true start_block = index+1 ##Handle end of bold text if list[index] == "</B>": if not is_bold: print "Error: Extra Close Bold" print "Bold [",start_block,":",index,"] ",\ list[start_block:index] is_bold = false start_block = index+1 get_bolds(poem)
출력을 보인다면 다음과 같다.
Bold [ 1 : 4 ] ['Jack', 'and', 'Jill'] Bold [ 11 : 15 ] ['fetch', 'a', 'pail', 'of'] Bold [ 20 : 23 ] ['down', 'and', 'broke'] Bold [ 28 : 30 ] ['Jill', 'came']
get_bold함수는 하나의 리스트를 불러들여 단어와 토큰으로 분리한다. 그 함수가 찾는 토큰은 굵은 글씨체의 시작을 나타내는 <B>
와 굵은 글씨체의 마지막을 나타내는 ' <\B>' 이다. 그 함수 get_bold는 진행하면서 처음과 마지막 토큰을 탐색한다.
리스트의 다음 사양은 그들을 복사하는 것이다. 여러분이 다음과 같이 간단한 어떤 것을 시도해 본다면 다음과 같다.
>>> a = [1,2,3] >>> b = a >>> print b [1, 2, 3] >>> b[1] = 10 >>> print b [1, 10, 3] >>> print a [1, 10, 3]
이것은 아마도 놀라워 보일 것이다. 왜냐하면 b 에 대한 변경이 a 를 변경한 결과가 되었기 때문이다. 상황은 'b = a' 서술문이 b 를 a 에 대한 참조점으로 만들었기 때문이다. 이것이 뜻하는 바는 b를 a의 다른 이름으로 생각해도 좋다는 것을 의미한다. 그러므로 b에 대한 어떠한 변경도 a 를 역시 변경시킨다. 그렇지만 b 전체에다 할당하는 함수를 사용하면서 a 를 변경하지 마라.
>>> a = [1,2,3] >>> b = a >>> b = b*2 >>> print a [1, 2, 3] >>> print b [1, 2, 3, 1, 2, 3]
이 경우에는 'b = b*2'서술문이 복사본 하나를 생성하므로 b 는 더 이상 a에 대한 참조점이 아니다. 기본적으로 여러분이 'whole_list_b = whole_list_a'와 같은 서술문을 가지고 있다면 여러분은 하나의 참조를 생성하고 있는 것이다. 여러분이 리스트를 인수로서 함수에 넘길 때에도 여러분은 역시 주소점을 생성하고 있는 것이다. whole_list_b 에 대한 부차적인 변경은 원래의 리스트를 변경할 것이다. 대부분의 경우에 여러분은 이러한 불일치에 대하여 걱정할 필요가 없다. 그렇지만 여러분은 리스트의 복사본을 가질 필요가 있을 때 실제로 하나의 복사본을 생성했는지 확실하게 해야만 한다.
리스트를 복사하는 여러 방법들이 있다. 대부분의 경우에 있어서 잘 작동하는 가장 간단한 것은 썰기(slice) 연산자이다.
>>> a = [1,2,3] >>> b = a[:] >>> b[1] = 10 >>> print a [1, 2, 3] >>> print b [1, 10, 3]
썰기 "[:]"는 리스트에 대한 복사본을 생성한다. 그렇지만 바깥쪽 리스트만 복사한다. 만약 그 리스트가 리스트를 포함하고 있다면 안 쪽의 리스트도 역시 복사될 필요가 있다. 여러분은 그것을 수동으로 할 수도 있게지만, 파이썬은 이미 그런 일을 하는 모둘을 포함하고 있다. 여러분은 copy 모듈에 있는 deepcopy 함수를 사용할 수 있다.
>>> import copy >>> a = [[1,2,3],[4,5,6]] >>> b = a[:] >>> c = copy.deepcopy(a) >>> b[0][1] = 10 >>> c[1][1] = 12 >>> print a [[1, 10, 3], [4, 5, 6]] >>> print b [[1, 10, 3], [4, 5, 6]] >>> print c [[1, 2, 3], [4, 12, 6]]
무엇보다도 a 는 배열의 배열이라는 것을 주목하라. 안쪽의 배열은 썰기 연산자로 정확하게 복사되지 않는다. 그렇지만 deepcopy로 c는 정확하게 복사된다. 잠-깐 : 이런게 의미가 있는가?
지금까지 여러분은 아마도 왜 참조가 사용되는지 도대체 이해가 안갈 것이다? 기본적인 이유는 속력 때문이다. 수천의 요소들 모두를 복사하는 것 보다는 그것들을 참조하는 편이 훨씬 더 빠르다. 그러지 않아야 할때 데이타가 변하는 괴이한 문제를 여러분이 가지더라도 참조에 관하여 여러분은 단지 이 사실만은 기억하라.