본문 바로가기
컴퓨터 프로그래밍/python

Python 컬렉션(Collection)

by JaeBaek 2020. 8. 13.

Collection (Wikimedia)

 

■ 컬렉션 관리 함수

★ 성적 산출

 컬렉션은 여러 개의 값을 저장한다는 면에서 기능적으로 비슷해 관리 방법도 유사합니다. 상호 대체가 가능하며 필요시 서로 변환도 가능합니다. 따라서 컬렉션의 가장 기본적인 동작은 요소를 모두 순회하며 읽어 내는 것입니다. 이것은 for문을 사용하면 간단하겠네요. 

 그러면 학생의 점수를 입력하고, 그 점수를 각 학생마다 출력하는 방식을 코딩해보도록 하겠습니다.

 

 

 

ex) 학생 score 출력

score=[95,93,94,91,80]
n=1
for i in score:
    print(n,"번 학생 점수 : ",i)
    n+=1

결과

 

 

 이 방법은 이전에도 해왔었지만 기본적인 python에서의 for문을 사용하는 방식입니다. 다른 방법으로 n+=1을 제거하고 각 위치를 꺼내는 방식으로 코딩을 한다면 다음과 같습니다. 개인적으로 matlab이나 c에서 쓰는 방법과 유사한 것 같습니다. 

score=[95,93,94,91,80]

for i in range(len(score)):

    print(i,"번 학생 점수 : ",score[i])

 

기존의 방법은 순서값과 요소값을 적절히 활용을 하여 각 번호에 맞는 점수를 출력을 하였는데 enumerate 내장함수를 사용을 하면 순서값과 요소값 두개를 모두 한꺼번에 구해 주는 내장 함수를 사용하면 편리합니다. 

 함수의 기본적인 형태는 enumerate( 요소값들 , 시작순서 ) 이고, 요소값들이 순서대로 시작순서와 함께 증가하며 출력이 됩니다. 따라서 enumerate 사용한 점수의 출력 코드는 다음과 같습니다.

score=[95,93,94,91,80]

for i,j in enumerate(score,1):

    print(i,"번 학생 점수 : ",j)

※ 여기서 i는 순서값에 해당하고 j는 요소값에 대응이 됩니다.

 

★ Zip

 zip 함수는 여러 개의 컬렉션을 합쳐 하나로 만드는 것입니다. 즉, 두 리스트의 대응되는 요소끼리 짝을 지어 튜플의 리스트를 생성하고, 두 개의 리스트를 선회할 때 편리합니다. 간단히 dic처럼 키값 요소값이 대응된다고 생각하면 될 것 같습니다.

 

ex) 요일-메뉴 연결하기

day=["월","화","수","목","금","토","일"]
food=["김치찌개","삼겹살","비빔밥","불고기"]
menu=zip(day,food)
for d,f in menu:
    print(d,"요일 음식 : ",f)

결과

 

결과를 보면 알 수 있듯이 food가 4개 밖에 없기 때문에 menu list의 길이도 4가 됩니다. 따라서 생성되는 튜플의 순서는 원본 리스트의 순서와 같습니다. zip( a , b )를 사용할 때 a와 b 중 어떤 것을 사용하든지 상관이 없습니다.

 

 

■ 람다 함수

★ filter

filter 함수는 리스트의 요소 중 조건에 맞는 것만 골라내는 것입니다. 첫 번째 인수는 조건을 지정하는 함수이고, 두 번째 인수는 대상 리스트입니다. 즉, 다시 말해서 filter(function, list) 의 기본 구조로 작성을 하시면 됩니다. 그럴려면 미리 함수를 정의해야겠죠.

 

filter

def score(s):

    if s<60:

        return s

score1=[45,89,72,53,94]

for s in filter(score,score1):

    print(s," 60점 미만은 불합격")

result

45  60점 미만은 불합격
53  60점 미만은 불합격

 위 코드를 통해서 다시 설명을 하자면 filter라는 함수는 어떠한 function을 이용해서 list를 판별을 하는 기능을 하고, 그 함수의 조건을 만족하는 반환값을 for문에서 사용을 한다고 생각하면 될 것 같습니다.

 

 

★ map

 map 함수는 모든 요소에 대해 변환 함수를 호출하여 새 요소값으로 구성된 리스트를 생성합니다. 인수 구조는 filter 함수와 동일하며 요소값을 어떻게 변경할 것인가는 첫 번째 인수로 전달된 변환 함수의 동작에 따라 달라집니다. 

map(function,list)

 

map

def score(s):

    return s*100

score1=[0.95,0.93,0.94,0.91,0.80]

for s in map(score,score1):

    print(s)

print(score1)

result

95.0
93.0
94.0
91.0
80.0
[0.95, 0.93, 0.94, 0.91, 0.8]

결과를 보면 알 수 있듯이 score1 list는 읽기만 할 뿐 변경되지 않습니다. 

 

 

★ lambda

 람다함수를 시작하기 전에 map 함수와 filter함수는 필터링과 변환을 위해서 다른 함수를 인수로 받았습니다. 이 함수를 호출하기 전에 인수로 전달할 함수부터 정의해야 하기 때문에 귀찮은 면이 있습니다. 이럴 때 간편하게 쓸 수 있는 것이 람다식입니다. 람다는 이름이 없고 입력과 출력만으로 함수를 정의하는 축약된 방법입니다.

기본구조

lambda 인수:식

 

 식을 보면 너무나 간단한 것을 알 수 있습니다. return문은 없지만 인수로부터 계산한 식을 바로 반환합니다. 따라서 lambda 함수를 이용하면 filter나 map함수에서 사용하기 위한 함수 정의를 하지 않고 lambda함수만으로 간단하게 나타낼 수 있는 것입니다.

 그러면 이전에 했던 filter함수와 map함수에서 했던 ex)를 다시 한번 간단하게 나타내보도록 하겠습니다.

 

filter with lambda

score1=[45,89,72,53,94]

for s in filter(lambda x:x<60, score1):

    print(s," 60점 미만은 불합격")

 

결과는 동일합니다. 하지만 함수를 정의하지 않아 단 3줄로 코드가 줄어든 것을 알 수 있습니다.

map with lambda

score1=[0.95,0.93,0.94,0.91,0.80]

for s in map(lambda x:x*100,score1):

    print(s)

# 마찬가지로 결과 동일



 

■ 컬렉션 사본

★ 리스트의 사본

기본적으로 변수는 서로 독립적입니다. 예를들어서 a=1 -> b=a => a=3 을 작성한다고 했을 때, b=3이 되지 않습니다. 순차적인 코드의 실행을 생각했을 때 당연한 것처럼 보입니다. 하지만 컬렉션에서는 어떻게 될까요? 결론은 같이 바뀝니다. 왜냐하면 두 리스트는 독립된 사본이 아니라 같은 메모리를 가지고 있기 때문입니다. 한 가지 예시를 들어보겠습니다.

 

Collection independence

list1=[1,2,3]

list2=list1  # 또는 list2=list1[:] 사용

print(list2)

list1[1]=10

print(list2)

result

[1, 2, 3]
[1, 10, 3]

 

위의 코드 결과를 보면 알 수 있듯이 list1의 두번 째 요소를 변경시켰는데 list2의 코드도 변경된 것을 알 수 있습니다. 즉, list2=list1 대입에 의해서 list2가 list1의 분신(?)이 된 것일 뿐 메모리의 확보가 된 것은 아닙니다. 추가적인 메모리 할당을 위해서는 어떻게 해야 할까요? 이때는 copy함수를 사용하시면 됩니다. 

 

copy

list1=[1,2,3]

list2=list1.copy()

list2[1]=10

print(list1)

print(list2)

result

[1, 2, 3]
[1, 10, 3]

 

이중 리스트의 경우에는 단순히 copy()를 사용하는 것만으로는 독립적으로 나타나지 않습니다. 

copy - 이중 리스트

list0=['a','b']

list1=[list0,1,2]

list2=list1.copy()

list2[0][1]='c'

print(list1)

print(list2)

result

[['a', 'c'], 1, 2]
[['a', 'c'], 1, 2]

ex) copy - 이중 리스트

list0=['a','b']

list1=[list0,1,2]

list2=list1.copy()

list2[0][1]='c'

print(list1)

print(list2)

결과

 

이중 리스트의 경우에는 완전한 사본을 만들기 위해서 깊은 복사를 수행해야 합니다. 이때는 deepcopy 함수를 사용합니다. (deepcopy는 copy의 모듈입니다.)

deepcopy

import copy

list0=['a','b']

list1=[list0,1,2]

list2=copy.deepcopy(list1)

list2[0][1]='c'

print(list1)

print(list2)

result

[['a', 'b'], 1, 2]
[['a', 'c'], 1, 2]

 

★ is 연산자

두 변수가 같은 객체를 가르키는지를 조사할 때 사용하는 기능입니다. 좌우 변수가 같으면 True, 다르면 False를 반환합니다.

is

list1=[1,2,3]

list2=list1

list3=list1.copy()

print("1==2",list1 is list2)

print("1==3",list1 is list3)

print("2==3",list2 is list3)

result

1==2 True
1==3 False
2==3 False

여기서  list2=list1을 통해서 실행시킨 문장은 True를 반환하고, list3=list1.copy()에서 2==3은 False를 반환하였습니다. 결국 여기서 알 수 있는 것은 1과 2는 같은 메모리를 공유하지만 1과 3 그리고 2와 3은 다른 메모리를 공유한다는 것을 알 수 있습니다.

 

 

 

 

 

'컴퓨터 프로그래밍 > python' 카테고리의 다른 글

Python 예외 처리 (exception process)  (0) 2020.08.14
Python 표준 모듈  (0) 2020.08.13
Python 사전(Dictionary)과 집합(Set)  (0) 2020.08.12
Python 리스트(list) & 튜플(tuple)  (0) 2020.08.12
Python 포맷팅(Format)  (0) 2020.08.12

댓글