Home Python Sequences
Post
Cancel

Sequence Type

Python의 Sequence type은 MutableImmutable Sequence Type으로 나뉜다.
Immutable Sequence Type에는 StringTuple이 있다.

Mutable Sequences Immutable Sequences
list string
bytearrays tuple
  range
  bytes

NOTE: Mutable은 내용의 변경이 가능한 Type이며, Immutable은 변경이 불가능하다.

tuple element의 값을 변경하는 코드를 실행해보자.

1
2
t = (1, 2, 3)
t[0] = 10
1
2
3
4
5
6
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-155b9e8fb284> in <module>()
----> 1 t[0] = 10

TypeError: 'tuple' object does not support item assignment

위 코드의 실행 결과처럼 tuple에 새로운 값을 assign하려고 하면 TypeError를 띄우게 된다.

반면 tuple안에 mutable sequence type인 list가 있는 경우,
list의 element는 수정이 가능하다.

1
2
>>> t = ([1, 2], 2, 3)
>>> t[0][0] = 10
1
([10, 2], 3, 4)

Concatenation and Repetition

Concatenate+ operator를 사용하여 할 수 있고,
Repetition* operator를 사용하여 할 수 있다.
그리고 ConcatenateRepetition은 언제나 새로운 Object를 반환한다.

Concatenation

1
2
3
4
5
6
7
8
# Concatenation
l1 = [1, 2, 3]
l2 = [4, 5, 6]
l3 = l1 + l2
print(f"l3: {l3}")
print(f"id of l1: {id(l1)}")
print(f"id of l2: {id(l2)}")
print(f"id of l3: {id(l3)}")
1
2
3
4
l3: [1, 2, 3, 4, 5, 6]  
id of l1: 2619302087680  
id of l2: 2619302081984  
id of l3: 2619308460288  

위의 결과를 보면 알 수 있듯이 Concatenation의 결과인 l3l1l2와 다른 메모리 주소를 보여준다.

아래의 Inplace-concatenation을 보면 메모리 주소가 변하지 않는 것을 볼 수 있다.

1
2
3
4
5
6
7
8
9
# inplace-concatenation
l1 = [1, 2, 3]
l2 = [4, 5, 6]
l3 = l1.extend(l2)
print(f"l1: {l1}")
print(f"l3: {l3}")
print(f"id of l1: {id(l1)}")
print(f"id of l2: {id(l2)}")
print(f"id of l3: {id(l3)}")
1
2
3
4
5
l1: [1, 2, 3, 4, 5, 6]  
l3: None  
id of l1: 2619302087680  
id of l2: 2619314922560  
id of l3: 140719011362992  

l3를 보면 None인 것을 볼 수 있는데 Inplace-concatenationReturn이 없이 자기 자신을 변경 시키는 것이 특징이다.

다른 Type의 Sequence를 Concatenation하면 TypeError를 띄운다

1
(1, 2, 3) + [4, 5, 6]
1
2
3
4
5
6
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-25-67a9e2ed8695> in <module>()
----> 1 (1, 2, 3) + [4, 5, 6]

TypeError: can only concatenate tuple (not "list") to tuple
1
'abc' + ['d', 'e', 'f']
1
2
3
4
5
6
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-26-8cbdd441adc1> in <module>()
----> 1 'abc' + ['d', 'e', 'f']

TypeError: must be str, not list

아래와 같이 해결 가능하다.

1
>>> (1, 2, 3) + tuple([4, 5, 6])
1
(1, 2, 3, 4, 5, 6)
1
>>> tuple('abc') + ('d', 'e', 'f')
1
('a', 'b', 'c', 'd', 'e', 'f')
1
>>> ''.join(tuple('abc') + ('d', 'e', 'f'))
1
'abcdef'

참고로 tuple은 immutable sequence type이므로 concatenation을 할 경우 New object를 생성한다.

Repetition

1
2
3
4
5
6
# Repetition
l1 = [1, 2, 3]
l2 = l1 * 3
print(l2)
print(f"id of l1: {id(l1)}")
print(f"id of l2: {id(l2)}")
1
2
3
[1, 2, 3, 1, 2, 3, 1, 2, 3]  
id of l1: 2619302087424  
id of l2: 2619314821952

Repetition도 마찬가지로 l2 의 메모리 주소가 l1과 다른 New object를 Return한다.


Slicing

sequence[start, stop, step] 으로 사용할 수 있다.
또한 start가 비어있으면 0을, stop이 비어있으면 맨 마지막을 가르킨다.
그리고 stop이 range를 벗어나도 문제가 없다.

1
2
>>> l = [1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> l[0:3], l[:3], l[3:6], l[6:9], l[6:], l[6:100]
1
([1, 2, 3], [1, 2, 3], [4, 5, 6], [7, 8, 9], [7, 8, 9], [7, 8, 9])

sequence[start:stop:step]sequence[slice(start, stop, step)]과 동일하다.

1
2
3
4
l = [1, 2, 3, 4, 5, 6, 7, 8, 9]
sl = slice(0, 3)
print(l[0:3])
print(l[sl])
1
2
[1, 2, 3]
[1, 2, 3]

-를 써서 slice도 가능한데 맨 마지막 위치가 -1로 시작해서 좌측으로 갈수록 -1씩 더해주면 된다.
그리고 step을 -1을 주면 반대로 slicing을 한다.

1
2
>>> l = [1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> l[-3:-1], l[::-1]
1
([7, 8], [9, 8, 7, 6, 5, 4, 3, 2, 1])

Finding in Sequences

Sequence 안에 element의 index를 찾는 법.
index(찾을것)

1
2
>>> s = "hello python"
>>> s.index('h')
1
0

Optional로 찾기 시작할 위치를 start로 지정가능 하며, optional로 end를 지정할 수도 있다.
index(찾을것, start, end)

1
2
>>> s = "hello python"
>>> s.index('h'), s.index('h', 5), s.index('h', 5, 13)
1
(0, 9, 9)

만일 찾고자하는 element를 찾지 못하면 ValueError를 띄운다.

1
2
>>> s = "hello python"
>>> s.index('h', 10)
1
2
3
4
5
6
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-25-669dc875185c> in <module>
----> 1 s.index('h', 10)

ValueError: substring not found

ValueError로 인해 프로그램이 종료되는 것을 방지하기 위해서,
아래와 같이 예외처리를 해 줄 수 있다.

1
2
3
4
5
s = "hello python"
try:
    s.index('h', 10)
except ValueError:
    print('finding element is not exist')
1
finding element is not exist

Caveats (주의사항)

list objectConcatenation을 하게 되면 Return되는 object는 New object이다.
하지만, copy된 list 내부의 element는 original element를 그대로 referencing하게 되어 같은 id를 가지게 된다.
element자체가 immutable object라면 element를 수정할 때 immutable이기 때문에 수정하려는 값으로 reference를 바꾸게 되어 문제가 없지만,
mutable object면 orinal object의 element를 수정할 때 copy본의 element도 같이 수정되는 의도치 않은 문제가 생길수 있게 된다.

  • 참고사항

    Mutable object: list, set, dict
    Immutable object: int, float, complex, bool, string, tuple, frozen set, range

1
2
3
4
5
a = [[1, 2]]
l = a + a
print(l)
print(id(l[0]), id(l[1]))
print(l[0] is l[1])
1
2
3
[[1, 2], [1, 2]]  
2619315234368 2619315234368  
True
1
2
a[0][0] = 50
print(l)
1
[[50, 2], [50, 2]]  

original list의 element를 수정하였으나 copy본인 l의 element가 다 바뀌어버리는 의도치 않은 결과가 나오게 된다.
이와 관련해서 다음 copy에 대해서 자세히 다뤄보도록 한다.


NEXT: Shallow Copy, Deep Copy


This post is licensed under CC BY 4.0 by the author.

Jekyll 테마를 이용해 GitHub 블로그 만들기

Python sys.stdout.flush()