리스트(List)
내용
리스트(List)
리스트(list)의 특성은 다음과 같습니다.
리스트(list)
- 대괄호([ ]) 내에 자료들을 입력
- 입력된 자료가 없는 빈 리스트 객체 생성 가능
- 숫자형와 문자형을 혼합하여 가질 수 있음
- 요소로 다른 리스트를 가질수 있음
- 요소의 수정이 가능 즉, 가변(mutable) 객체
다음 코드로 생성된 리스트 객체 ls1, ls2, 그리고 ls3은 각각 수치형, 문자형, 그리고 두 자료형의 혼합으로 구성되어 있습니다.
lst1=[2, 1, 5];lst1
[2, 1, 5]
lst2=['a', 'python', 'kotlin'];lst2
['a', 'python', 'kotlin']
lst3=[23, "computer", 98, "apple"];lst3
[23, 'computer', 98, 'apple']
객체 ls4는 리스트내에 다른 리스트를 요소로 포함하고 있습니다.
lst4=[1, ["car", "computer"], 2,["apple, pear"]];lst4
[1, ['car', 'computer'], 2, ['apple, pear']]
리스트는 가변객체(mutable)
리스트는 1개 이상의 요소를 가지며 각 요소에 순차적으로 인덱스가 자동으로 할당됩니다. 그러므로 문자열과 같이 리스트 역시 시퀀스 객체이며 그 인덱스를 사용하여 특정한 요소에 접근할 수 있습니다. 또한 가변 객체인 리스트의 각 요소는 그 인덱스를 사용하여 수정, 치환, 삭제 할 수 있습니다.
lst1[0], lst1[-3]
(2, 2)
lst1[2], lst1[-1]
(5, 5)
리스트내에 다른 리스트가 내재되어 있을 경우는 식 1과 같이 첫번째 리스트의 인덱스와 내재된 리스트의 인덱스를 연이어 사용합니다.
객체이름[첫번째리스트의 인덱스][두번째리스트의 인덱스]... | (식 1) |
lst4=[1, ["car", "computer"], 2,["apple, pear"]]; lst4
[1, ['car', 'computer'], 2, ['apple, pear']]
lst4[1]
['car', 'computer']
lst4[1][1]
'computer'
리스트 객체의 인덱스와 슬라이싱 규칙을 적용하여 요소를 수정할 수 있습니다.
lst4[0]=100 lst4
[100, ['car', 'computer'], 2, ['apple, pear']]
lst4[1][1]='노트북' lst4
[100, ['car', '노트북'], 2, ['apple, pear']]
x=[1,2,3,4,5,6,7] x[:3]=[10, 20, 30] x
[10, 20, 30, 4, 5, 6, 7]
슬라이싱 규칙의 형식 [::-1]를 사용하여 리스트의 요소들을 역순서로 재배치 할 수 있습니다.
x=[1,2,3,4,5,6,7] x1=x[::-1] x1
[7, 6, 5, 4, 3, 2, 1]
리스트 객체의 복사
리스트는 변경가능한 가변객체 입니다. 할당연산자("=")를 사용하여 리스트 객체를 복사할 경우 얕은 복사(shallow copy)가 이루어집니다. 즉, 객체 b와 a는 같은 참조점을 가지며 서로 연결(상호참조)되어 한 객체의 변화는 다른 객체의 변화를 일으킵니다.
a=[20, 5, 1] b=a b==a
True
b is a
True
b[0]='a' a, b
(['a', 5, 1], ['a', 5, 1])
다음 코드에 사용한 메소드 x.append(y)
는 객체 x의 마지막에 요소 y를 첨가합니다. 이 메소드는 리스트를 포함한 가변 컬렉션 객체에 공통을 적용됩니다.
a.append('c') a, b
(['a', 5, 1, 'c'], ['a', 5, 1, 'c'])
위 코드에서 객체 b는 객체 a 자체를 할당한 것으로 동일한 참조점을 갖습니다. 그러므로 객체 a 또는 b 두 객체 중 하나의 객체가 수정되거나 새로운 요소가 보충되면 다른 객체 역시 수정됩니다. 즉, 얖은 복사가 이루어집니다.
다음과 같이 객체 b1에 슬라이싱을 적용하여 객체 a1의 각 요소를 직접 할당하면 두 리스트 객체는 연결되지 않으므로 상호 영향을 줄 수 없는 깊은복사(deep copy)가 실행됩니다. 즉, 객체 b1은 리스트 객체인 a1을 참조하는 것이 아니라 그 객체의 각 요소를 참조합니다. 그러므로 b1의 참조 대상이 달라지는 것은 a1에 영향을 주지 못합니다. 물론 반대의 경우 역시 서로 영향을 주지 않습니다.
a1=[20, 5, 1] b1=a1[:] b1
[20, 5, 1]
a1==b1, a1 is b1
(True, False)
id(a1),id(b1)
(1583889740288, 1583889740032)
위 결과와 같이 두 객체 a1, b1은 같은 값이지만 다른 참조점을 가리키므로 다른 객체입니다. 그러나 다음 결과와 같이 각 요소에 대한 참조점은 같습니다.
print(a1[0] is b1[0]) print(a1[1] is b1[1]) print(a1[2] is b1[2])
True True True
위 코드들의 결과인 리스트의 얕은 복사와 깊은 복사를 시각화하면 그림 1과 같습니다.
그림 1(b)의 깊은 복사에서 나타낸 것과 같이 객체 a1과 b1은 같은 요소들을 가진 다른 객체이므로 한 객체의 변화는 다른 객체에 영향을 주지 못합니다.
b1[0]='a' a1, b1
([20, 5, 1], ['a', 5, 1])
즉, a1과 b1은 값은 같지만 다른 참조점을 갖음을 의미합니다. 위와 같이 인덱스를 사용하여 깊은 복사를 수행하는 과정은 리스트 메소드인 .copy
를 사용하여 달성할 수 있습니다. 다음 객체 a는 요소로 다른 리스트를 갖는 객체입니다. 다음 코드에서 b는 a에 대한 깊은 복사를 실시합니다. 즉, a의 각 요소를 참조한 것입니다. 이 경우 b는 a의 요소인 내재된 리스트인 [10, 20]을 참조하는 것으로 이 리스트에 대한 복사는 얕은복사가 실행됩니다.
a=[1, [10,20]] b=a.copy() b
[1, [10, 20]]
리터럴인 첫 번째 요소는 깊은 복사가 이루어 집니다.
b[0]=3 b, a
([3, [10, 20]], [1, [10, 20]])
그러나 a의 두 번째 요소인 리스트의 복사과정은 좀 더 복잡합니다. 객체 b는 내재된 리스트의 각 요소가 아니라 리스트 자체를 복사한 것으로 그림 1(a)와 같이 이루어집니다. 즉, 얕은 복사가 이루어 집니다.
b[1][0]=0.1 b, a
([3, [0.1, 20]], [1, [0.1, 20]])
a==b
True
a is b
False
위 결과와 같이 객체 a와 b의 깊은 복사가 이루어지지만 내재된 리스트의 경우 다음 코드의 결과와 같이 앝은 복사가 이루어집니다.
a[1] is b[1]
True
a[1][0]=1000 a, b
([1, [1000, 20]], [1, [1000, 20]])
객체의 복사를 위해 특정된 copy 모듈의 함수들을 사용할 수 있습니다. 이 모듈의 copy()
함수는 위와 동일한 결과를 반환하지만 다른 함수 deepcopy()
는 내재된 리스트 객체에 대해서도 깊은 복사를 실행합니다.
import copy a=[1, [10,20]] b=copy.copy(a) b
[1, [10, 20]]
한 객체에서 리털러인 첫번째 요소의 변화는 다른 객체의 영향은 없습니다. 즉, 깊은 복사를 시행합니다.
a[0] is b[0]
True
a[1][0] is b[1][0]
True
b[0]='7' a, b
([1, [10, 20]], ['7', [10, 20]])
그러나 리스트 객체인 두 번째 요소의 경우는 객체 상호간에 영향을 주는 얕은 복사가 실행됩니다. 즉, copy()
함수는 .copy()
메소드와 정확히 같은 결과를 반환합니다.
b[1][0]='x' a, b
([1, ['x', 20]], ['7', ['x', 20]])
copy.deepcopy()
함수는 내재된 리스트에 대해 깊은 복사를 실행합니다.
c=copy.deepcopy(a) c, a
([1, ['x', 20]], [1, ['x', 20]])
c[0]="deep" a, c
([1, ['x', 20]], ['deep', ['x', 20]])
c[1][1]='copy' a, c
([1, ['x', 20]], ['deep', ['x', 'copy']])
위에서 소개한 리스트 객체의 복사는 다른 수정가능한 컬렉션인 사전형에도 적용됩니다.
a=[1, {'ten': 'Ten', 'two': 2}] bc=copy.deepcopy(a) c
[1, {'ten': 'Ten', 'two': 2}]
c[1]['ten']=10 c
[1, {'ten': 10, 'two': 2}]
a
[1, {'ten': 'Ten', 'two': 2}]
리스트의 대표적인 메소드
리스트 객체 역시 클래스로 작성되었습니다. 그러므로 리스트 객체 내에서만 작동하는 고유한 속성과 메서드를 포함하고 있으며 그 중 사용 빈도가 높은 대표적인 메소드를 표 1에 수록하였습니다.
다른 컬렉션인 튜플, 사전, 그리고 집합형 역시 클래스로 작성되었으므로 각각 고유한 속성과 메서드를 가집니다. 그러나 같은 이름의 속성과 메서드들로 존재하는 경우가 많아 표 1에서 소개하는 메소드들의 대부분이 다른 컬렉션 자료형에서도 작동합니다. 물론 이러한 공통 작동에는 클래스 상속 등 다양한 작동 기전이 작용하지만 일부 속성과 메서드들의 이름이 같다고 인식하는 것으로 충분합니다. 각 객체에 대해 dir()
함수를 적용하여 고유한 속성과 메서드를 확인할 수 있습니다.
메소드 | 내 용 |
---|---|
x.append(y) | 리스트 x의 마지막에 요소 y를 첨가 첨가되는 요소의 자료형이 유지 |
x.extend(y) | 리스트 x에 마지막 요소 다음에 y를 첨가 y는 리스트등의 컬렉션이며 그 자료형은 유지되지 않음 |
'+' 연산자 | 두 리스트를 결합 이 연산은 위의 extend() 메서드와 같은 결과를 반환 |
'*' 연산자 | 리스트의 반복 |
x.insert(ind, val) | 객체 x에서 지정한 인덱스 위치(ind)에 값(val)을 삽입 인수 ind는 정수이어야 합니다. 즉, 삽입할 위치는 1개 이어야 합니다. |
del x, del x[ind] | 키워드 del을 사용하여 객체 x 또는 지정한 인덱스의 요소를 삭제 |
x.remove(val) | 객체 x에 존재하는 요소 val을 삭제, val은 존재해야 합니다. |
x.pop(ind) | 객체 x내 지정한 인덱스(ind)에 해당하는 요소를 삭제 ind가 없을 경우 마지막 요소를 제거 |
x.clear() | 객체 x의 모든 요소들을 제거 |
x=[], x[index]=[] | 객체 x의 원하는 인덱스(index)에 빈 리스트를 할당함으로서 삭제 할 수 있음 |
x.count(y) | 객체 x의 요소들 중에 y의 갯수를 반환합니다. |
x.index(y) | 객체 x의 요소들 중에 y의 index를 반환합니다. 위 두 메서드 모두 y가 여러개일 경우 처음의 index만을 반환합니다. |
다음은 인덱스를 사용하여 리스트 객체의 요소를 호출하는 예로서 대응하는 요소가 없을 경우 예외(에러)가 발생합니다.
x=[1,2,3] x[3]
IndexError: list index out of range
리스트 객체의 마지막에 요소를 첨가하기 위해서는 .append()
와 .extend()
메소드를 적용합니다. 이 두 메소드의 차이는 첨가하는 객체의 자료형의 유지 여부에 있습니다.
x.append(4); x
[1, 2, 3, 4]
x.append([5]); x
[1, 2, 3, 4, [5]]
위 코드와 같이 .append()의 경우는 첨가되는 객체의 자료형은 유지 됩니다. 그러나 다음 코드의 결과와 같이 x.extend(y)는 객체 y 자체가 아닌 y의 각 요소가 호출되어 리터럴으로서 객체 x에 삽입되므로 y의 자료형은 잃어버립니다. 이 메소드의 인수 객체 y는 요소 각각을 호출할 수 있는 이터러블 객체(iterable)입니다. 그러므로 숫자 리터럴(하나의 숫자)은 실행되지 않습니다.
y=['a','b','c'] x.extend(y); x
[1, 2, 3, 4, 'a', 'b', 'c']
x.extend(6); x
TypeError: 'int' object is not iterable
산술 연산자 +와 *는 리스트 객체들을 대상으로 다른 연산을 실행합니다. 즉, +
연산자는 두 리스트의 결합, 그리고 *
연산자는 리스트 객체의 반복을 위해 사용합니다.
x=[1,2,3] y=[4,5] x+y
[1, 2, 3, 4, 5]
3*x
[1, 2, 3, 1, 2, 3, 1, 2, 3]
리스트 객체의 지정된 위치에 값을 삽입하기 위해 .insert(index, value)
을 적용합니다.
x=[1,2,3] x.insert(1, 4); x
[1, 4, 2, 3]
이 메소드는 다음과 같이 컬렉션 자료형을 사용하여 여러 개의 값들을 전달할 수 있지만 지정을 위한 인덱스는 정수(스칼라)이어야 합니다. 다음 코드의 첫 번째 인수인 [2, 3]은 리스트로서 인덱스로 지정할 수 없습니다.
x.insert([2,3], [20, 24])
~~ TypeError: 'list' object cannot be interpreted as an integer
x.insert(3, [20, 24]) x
[1, 4, 2, [20, 24], 3]
다음은 리스트 뿐만 아니라 파이썬으로 작성된 모든 객체나 객체의 요소를 제거하기 위한 다양한 키워드, 메소드들에 대한 예입니다(표 3.2.1).
x=[1, 4, 12, 21, 33, 2, 3] del x[2]; x
[1, 4, 21, 33, 2, 3]
x.remove(1); x
[4, 21, 33, 2, 3]
x.pop(2) #제거되는 원소를 반환
33
x.pop() #마지막 원소 제거
3
x
[4, 21, 2]
x.clear() x
[]
요소가 없는 빈 리스트도 객체입니다. 그러므로 다음 코드와 같이 빈 리스트를 할당하여 요소(들)을 삭제할 수 있습니다.
x=[1, 4, 12, 21, 33, 2, 3] x[1]=[];x
[1, [], 12, 21, 33, 2, 3]
x[3:6]=[]; x
[1, [], 12, 3]
x=[]; x
[]
.count()
를 사용하여 리스트 내의 특정한 요소의 갯수를 확인합니다.
x=[1,2,1,1,2,4,5,5] x.count(1)
3
.index()
를 사용하여 지정한 인덱스에 대응하는 값을 확인합니다.
x.index(4)
5
리스트 객체는 하나이상의 요소들로 구성되어 있으며 각 요소의 자료형은 이질적인 것일 수 있습니다. 그러므로 요소 하나를 호출할 경우 그 요소의 자료형을 유지하지만 슬라이싱에 의해 두 개 이상의 요소들을 호출할 경우 리스트가 됩니다.
a=[1,2,'리스트', [3,4]] a[0]
1
type(a[2])
str
a[0:2]
[1, 2]
type(a[0:2])
list
댓글
댓글 쓰기