본문 바로가기

PROGRAMMING

[혼공학습단] 혼자 공부하는 파이썬 학습단 3주차 미션

 

[기본 미션] 리스트와 딕셔너리, 범위

이번 주 진도는 리스트와 딕셔너리, 범위, 그리고 반복문에 대한 내용이었다. 리스트나 딕셔너리가 필요한 이유는 '변수는 하나의 값을 가져야만 한다'라는 한계를 극복하기 위해서다. 만약 학생의 점수를 저장하는 변수가 있다고 할 때, 학생의 수에 변동이 있거나, 학생이 응시하는 과목의 수가 변하여 그에 대한 변수를 계속 만들어야 한다면? 변수 선언하는데만 한나절이 걸릴 것이고, 그것을 수정하는데도 한나절은 족히 걸릴 것이다. 그래서 프로그래밍 언어에서는 하나의 변수로 데이터의 묶음을 가지고 다니기 위해서 리스트나 딕셔너리 같은 자료구조를 구현하여 사용한다.

 

1. 리스트

리스트란 각각의 값들을 모아서 사용할 수 있게 하는 것이다. 배열 자료구조 비슷한 것이라고 생각하면 되겠다. 하지만 파이썬의 리스트에서는 종래 배열의 단점을 극복하는 여러 가지 요소가 있다.

첫 번째, 리스트는 길이 조절이 자유롭다. 기본 배열의 최대 단점(이라고 내가 생각하는)은 선언할 때 지정한 길이를 변경시킬 수 없는 것이다. 따라서 그러한 배열에 요소를 추가하거나 삭제하기 위해서는 배열을 복사해서 새로 선언하는 등의 귀찮음이 있었고, 인덱스가 하나라도 넘치면 배열은 생각하기를 그만두고 장비를 정지했었다. 그래서 Java에서는 배열의 한계를 극복한 컬렉션을 제공하는데, 파이썬에서는 그런 걱정은 하지 않고 기본적으로 리스트에 제공되는 함수를 사용해서 리스트를 씹고(생성), 뜯고(조회), 맛보고(수정), 즐길(삭제) 수 있다. 그냥 4가지라서 씹고 뜯고 맛보고 즐긴다고 비비고 있다. (히히)

 

list_a = ['브레드', '윌크', '초코', '치즈', '소세지', '감자칩']
# 1.5. 리스트에 요소 추가하기
# 1.5.1. append
list_a.append('마카롱')
print(list_a)

# TypeError: list.append() takes exactly one argument (2 given)
# list_a.append('케이크여왕', '케이크공주')
# print(list_a)

# 1.5.2. insert
list_a.insert(3, '우유식빵')
print(list_a)

# 1.5.3. extend
list_a.extend(['케이크여왕', '케이크공주'])
print(list_a)

print()
# 비파괴적 함수와 파괴적 함수

# 1.6. 리스트에서 요소 제거하기
# 1.6.1. del 키워드
del list_a[2]
print(list_a)

del list_a[2:4]
print(list_a)

# 1.6.2. pop
list_a.pop(3)
print(list_a)

# pop() 함수에 파라미터를 아무것도 주지 않으면 자동으로 -1 인덱스가 설정되어 가장 마지막 요소가 삭제됨
list_a.pop()
print(list_a)

# 1.6.3. remove
list_a.remove('마카롱')
print(list_a)

# 1.6.4 clear
list_a.clear()
print(list_a)

print()
기능 함수 설명
추가 append(요소) 리스트의 가장 마지막에 요소를 추가한다.
insert(인덱스, 요소) 해당하는 인덱스에 요소를 삽입하고 원래 존재했던 요소들은 하나씩 뒤로 민다.
extend(요소 배열) 요소 배열에 있는 값들을 모두 리스트에 추가한다.
삭제 del 리스트이름[인덱스]
del 리스트이름[인덱스 범위]
해당하는 인덱스 또는 인덱스 범위에 해당하는 요소를 삭제한다.
pop(인덱스) 해당하는 인덱스에 있는 요소를 삭제한다.
remove(요소) 해당하는 요소가 존재하면 리스트에서 삭제한다.
clear() 리스트에 있는 요소를 모두 삭제한다.

두 번째, 리스트는 여러 가지 자료형을 한데 넣을 수 있다. 다른 언어는 배열이나 리스트를 선언할 때 사용한 타입이나 제네릭을 꼭 지켜서 값을 넣어야 하지만, 파이썬은 변수를 선언할 때 명시적인 자료형을 선언하지 않는 만큼 리스트 안에 다양한 값을 넣을 수 있는 특징이 있다. (Object로 선언하면 안 되나? 아 좀... 자바맨 숙이고 있어)

# 1.2. 다양한 자료형 리스트
list_b = ['문자열', 123, 4.5, True, False]
print(list_b[0])
print(list_b[1])
print(list_b[2])
print(list_b[3])
print(list_b[4])

리스트의 요소에 접근하기 위해서는 문자열과 같이 0부터 리스트 길이 - 1 범위의 인덱스로 접근할 수 있다. 또한 인덱스 범위를 넘어가게 되면 존재하지 않는 위치의 요소를 참조하게 되어 IndexError가 발생한다. (에러 이름 너무 짧고 좋다) 그러나 주의할 점이 하나 있는데, 파이썬에서는 리스트의 요소를 음수로 참조할 수 있다.

print(list_a[-1])

그렇기 때문에 무조건 0 이하의 숫자 또는 리스트 길이 이상의 숫자를 넣으면 IndexError가 발생하는 것이 아니라, 음수로 역방향 참조도 할 수 있다는 것을 알아둬야 하겠다.

 

비파괴적인 것과 파괴적인 것

프로그래밍에서는 원본을 유지하되 새로운 결과를 돌려주는 비파괴적이라고 하고, 원본에 직접적인 영향을 주는 경우에는 파괴적이라고 한다. 예를 들어 연산자로 리스트를 조작하거나 조회할 때는 그 결과가 리스트 그 자체가 아닌 새로운 리스트가 생기는 경우가 많다. 하지만 추가, 수정, 삭제와 같이 리스트를 조작하는 함수를 사용하였을 때는 리스트의 원소에 변화가 생긴다. 이와 같은 경우를 비파괴적-파괴적이라고 지칭한다. 내가 리스트로 무엇을 하고 싶은지를 잘 생각하고 비파괴적으로 구현할지, 파괴적으로 구현할지 정하는 것이 좋겠다.

 

2. 딕셔너리

딕셔너리는 데이터가 0번지 부터 줄줄이 사탕으로 이어진 리스트와 달리 키-값의 조합으로 데이터를 저장하는 구조이다. 키-값으로 데이터를 저장하는 방법은 Map과 비슷하다고 할 수 있다. 하지만 자료형을 유연하게 넣을 수 있다는 데에서 약간 차이가 있다.

 

딕셔너리 선언하기

# 1.1. 딕셔너리 선언하기
dict_a = {
    'name': 'Toshiya',
    'part': 'Bass'
}

print(dict_a)
print(dict_a['name'])
print(dict_a['part'])

print()

딕셔너리를 선언하기 위해서는 중괄호 안에 키 : 값으로 이루어진 데이터 쌍을 컴마로 이어서 적으면 된다. 하지만 이때 키의 이름으로 식별자를 입력하는 경우가 있는데 그럴 때는 선언 전에 식별자를 정의하여 오류가 나지 않도록 하자.

 

딕셔너리 요소에 접근하기

# 1.2. 딕셔너리 요소에 접근하기
dict_b = {
    'name' : '상품권 5만원권',
    'price' : 50000,
    'type' : '종이 상품권'
}

print(dict_b)
print('name', dict_b['name'])
print('price', dict_b['price'])
print('type', dict_b['type'])
print()

딕셔너리에 저장된 요소에 접근하기 위해서는 딕셔너리 이름[키]와 같이 접근하면 된다. 앞으로 딕셔너리에 데이터를 추가하거나 수정하고 삭제할 때, 모두 딕셔너리 이름[키]를 기반으로 실행할 수 있다.

 

# 1.3. 딕셔너리에 값 추가/제거하기
dict_a['hometown'] ='Nagano'
print(dict_a)

dict_a['weakpoint'] = ''
print(dict_a)
del dict_a['weakpoint']
print(dict_a)
print()

# key = input('접근하고자 하는 키 ')
key = 'name'
if key in dict_a:
    print(dict_a[key])
else:
    print('Cannot find key', key)

print()

value = dict_a.get('aaa')
print('value :', value)

# value == None
if value is None:
    print('The key doesn\'t exist.')

print()

# for and dictionary
for key in dict_a:
    print(key, ':', dict_a[key])

print()

위 연습에서는 딕셔너리 dict_a에 'hometown'이라는 키를 추가하고 그 값을 'Nagano'로 지정하였다. 그리고 'weakpoint'라는 키를 추가했고 아무 값이나 집어넣었다. 그리고 del 키워드를 이용하여 'weakpoint' 키와 그에 해당하는 값을 모두 지웠다. (그렇다, 토느님은 단점 따위 없는 것이다.)

 

또한 in 키워드를 이용하여 딕셔너리에 저장된 키를 조회할 수 있다. 키는 딕셔너리 내부에 여러 개 존재하므로 for 반복문을 이용해서 딕셔너리에 있는 모든 키를 조회할 수 있겠다.

 

그리고 딕셔너리가 제공하는 get 함수를 이용하여 매개변수로 키를 집어넣었을 때, 그 키에 해당하는 값을 반환받을 수 있다. 그러나 해당하는 키가 없을 때에는 반환되는 값이 None으로 설정되는데, 그런 점을 이용하여 딕셔너리에서 특정 키에 해당하는 값이 없을 때 특정한 기능을 하도록 if문을 작성할 수 있다. 책에서는 if문에 == 연산자를 사용하였으나, 파이참의 suggestion으로 is라는 연산자를 사용해 보았다.

 

numbers = [1,2,3,4,5,1,3,4,5,6,2,3,4,5,6,7,2,3,1]
counter = {}

for number in numbers:
    val = counter.get(str(number))

    if val is None:
        counter[str(number)] = 1
    else:
        counter[str(number)] += 1

print(counter)

위 코드는 확인문제 3번에 대한 내용이다. 해당하는 키(숫자)에 해당하는 값이 없을 때에는 딕셔너리 counter에 키로 숫자를 설정하고 등장 횟수를 1로 초기화하였다. 그러나 키에 해당하는 값이 있을 때에는 그 값을 1씩 늘리는 식으로, 리스트에 있는 숫자들의 등장 개수를 딕셔너리로 옮기는 것이 가능하다.

 

3. 범위

파이썬에서는 range()라는 함수를 사용하여 특정한 범위의 숫자 목록을 만드는 것이 가능하다. 보통 1~3개의 파라미터를 선택하여 만들 수 있다. 각각의 파라미터 개수에 따라 생성되는 범위는 다음 표와 같다.

파라미터 개수 생성되는 값의 범위 설명
1 0 ~ 파라미터 - 1 초기값은 0으로 시작하며 파라미터 - 1의 값까지 1씩 늘려가며 사용할 수 있다.
2 첫번째 파라미터 ~ 두번째 파라미터 - 1 초기값은 첫번째 파라미터 값이며 두번째 파라미터 - 1의 값까지 1씩 늘려가며 사용할 수 있다.
3 첫번째 파라미터 ~ 두번째 파라미터 - 1 초기값은 첫번째 파라미터 값이며 두번째 파라미터 - 1의 값까지, '세번째 파라미터 값'씩 늘려가며 사용할 수 있다.

 

range() 함수는 for문과 결합해서 사용하면 좋다. for에서 필요한 초기식, 조건식, 증감식을 range() 함수에서 생성되는 값으로 모두 처리할 수 있기 때문이다.

초기식 : 시작값
조건식 : 변수가 끝 값보다 작을 때까지
증감식 : 파라미터 지정이 없는 한 1

 

# 1. 범위
a = range(5)
print(a)
print()

a = range(1, 4)
print(a)
print()

a = range(0, 10, 2)
print(a)
print(list(a))

print()

 

이렇게 다양한 데이터를 가지고 다닐 수 있는 리스트, 딕셔너리, 범위를 활용하면 여러 개의 데이터를 처리하는 것도 손쉽게 할 수 있겠다.


[추가 미션] p. 157의 1번 문제 인증샷

# [미션]
list_a = [0, 1, 2, 3, 4, 5, 6, 7]

list_a.extend(list_a)
print(list_a)

list_a = [0, 1, 2, 3, 4, 5, 6, 7]
list_a.append(10)
print(list_a)

list_a = [0, 1, 2, 3, 4, 5, 6, 7]
list_a.insert(3, 0)
print(list_a)

list_a = [0, 1, 2, 3, 4, 5, 6, 7]
list_a.remove(3)
print(list_a)

list_a = [0, 1, 2, 3, 4, 5, 6, 7]
list_a.pop(3)
print(list_a)

list_a = [0, 1, 2, 3, 4, 5, 6, 7]
list_a.clear()
print(list_a)

 

결과는 다음과 같다.

와우.

 


벌써 절반이나 왔다. 나머지도 열심히 해야지.

아 맞다.

내가 2주차 우수혼공단이라니~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!!!! so - ri - jil - ro ~~~~~~~~~~~~~~!!!!!!!!!! 아 뭔가 오만데 자랑하고 싶은데 내 체면상(?) 소소하게 자랑했다. 이 영광을 족zzang님께 바칩니다.

 

근데

맞춤법 검사하다가 표에 있는 내용 날려서 다시 씀

zzㅏ증 zㅣdㅐ로dㅏ~~~~~~~~~!!!!!!!