본문 바로가기

파이썬기초/파이썬기본개념1

[데이터 과학을 위한 파이썬 프로그래밍] 03. 화면 입출력과 리스트 (#파이썬 공부기록)

Chapter 03 화면 입출력과 리스트

01. 파이썬 프로그래밍 환경

02. 화면 입출력

03. Lab: 화씨온도 변환기

04. 리스트의 이해

05. 리스트의 메모리 관리 방식

 

01. 파이썬 프로그래밍 환경

[1] 사용자 인터페이스

: [컴퓨터에 명령을 입력할 떄 사용하는 환경]

대표적인 사용자 인터페이스는 GUI (Graphical User Interface)다.

GUI환경에서는 마우스와 아이콘 같은 도구들이 실행되는데,

예를 들어 페이스북에서 ‘친구추가’ 아이콘을 클릭하면 명령이 동작해 기능이 실행된다.

[2] CLI 환경

: [마우스 클릭 아닌 키보드만으로 명령 입력하는 환경]

키보드를 사용하여 텍스트를 입력하면, 이 입력값이 작성한 프로그램에 의해 가공된다.

매우 오래된 컴퓨터 사용자 인터페이스 체계로, 모든 운영체제(윈도, 맥, 리눅스…)에서 기본으로 지원한다.

예를 들어 파이썬을 설치하며 사용한 cmd(command window)창, 즉 명령어창은 윈도에서 제공하는 대표적인 CLI환경이다.

 

 

02. 화면 입출력

[1] 표준입력함수 : input() 함수

: 사용자가 문자열을 콘솔 창에 입력할 수 있게 해준다.

print("Enter your name:")
somebody = input() #콘솔 창에서 입력한 값을 somebody에 저장
print("Hi", somebody, "How are you today?")
Enter your name: <입력 대기>
gimi <사용자 입력 >
Hi gimi How are you today? <출력>

 

[2]표준출력함수 : print() 함수

  • print() 함수 안에 있는 콤마(,)

: 한 칸을 띄고 화면에 출력된다. 콤마를 사용하면 여러 값을 연결해 화면에 출력할 수 있다.

비슷한 방법으로 문자형 간에 +기호를 연결해 출력할 수 있다.

“+”기호 “,”콤마의 차이점은 “+”기호는 문자형 자료형이어야만 하지만 콤마는 변수의 자료형과 관계 없이 출력할 수 있다.

temperature = float(input("온도를 입력하세요")) #입력 시 바로 형변환
print(temperature)
온도를 입력하세요: 10 <입력 대기 및 사용자 입력>
10.0 <출력> #float()함수로 인해 실수형으로 출력됨

 

 

[3]파일 입출력 정리

데이터를 입력받고 출력하는 input() 함수와 print() 함수에 대해 간단하게 학습하였다.

이처럼 파이썬으로는 CLI 기반의 프로그램을 주로 다루며, 이는 파이썬의 스크립트 언어적 특성과 데이터 과학 분야에서의 다양한 활용으로 이어진다.

 

03. Lab: 화씨온도 변환기

(섭씨온도 celsius는 물의 어는 점을 0도, 끓는 점을 100도로 정하여 0부터 100도까지 100등분하여 온도를 측정한 온도다.

화씨온도 fahrenheit 는 물의 어는 점을 32도, 끓는 점을 212도로 하여 0부터 212까지 180등분하여 측정한 온도다.)

화씨온도 변환기 프로그램은 섭씨온도를 화씨온도로 변환해주는 간단한 프로그램이다.

섭씨온도와 화씨온도의 변환 공식 : 화씨온도('F) = ( 섭씨온도('C) * 1.8 ) + 32

c = input()
f = (float(c) * 1.8) + 32

print("섭씨온도:", c)
print("화씨온도:", f)

 

 

04. 리스트의 이해

[1] 리스트가 필요한 이유

리스트 : 프로그래밍언어에서 가장 많이 사용하는 자료형이며 프로그래밍에서는 배열이라고도 한다.

예를 들어 학생 100명의 성적을 채점해야 할 때 100개의 변수를 만들면 코드가 너무 길어져 하나하나 입력하기 쉽지 않고 변수에 값을 할당하기도 어려워 한 개의 변수에 모든 값을 할당하는 방식을 사용하는 것이 파이썬에서는 리스트(프로그래밍에서는 일반적으로 배열)다.

 

[2]리스트의 개념

리스트는 한 개의 변수에 여러 값을 할당하는 자료형이다.

리스트처럼 여러 데이터를 하나의 변수에 할당하는 기법을 시퀀스자료형이라고 한다. 시퀀스자료형은 여러 자료를 순서대로 넣는다는 뜻이다.

리스트는 하나의 자료형으로만 저장하지 않고, 정수형이나 실수형 같은 다양한 자료형을 포함할 수 있다.

colors = ['red', 'blue', 'green']

 

: ‘colors’ 변수 하나 생성하고 리스트 자료형 할당한 경우다.

: 리스트 안에 있는 값을 각각 ['red', 'blue', 'green'] 형태로 할당하였고,
colors라는 변수는 3개의 값을 가지며 각각의 값은 문자형의 'red', 'blue', 'green'인 것이다.

 

3.1 인덱싱

인덱싱 : 리스트 안에 있는 값에 접근하기 위해, 이 값의 상대적인 주소를 사용하는 것.

주소는 간단히 말해 첫 번째 값을 0으로 했을 때, 첫 번째 값과 얼마나 떨어져 있는 지를 표현한 값으로 일반적으로 인덱스 주소 또는 인덱스값이라 한다.

>>>colors = ['red', 'blue', 'green']
>>>print(colors[1])
blue
>>>print(colors[2])
green
>>>print(len(colors))
3

 

3.2 슬라이싱

슬라이싱 : 리스트에서 파생된 강력한 기능 중 하나로, 리스트의 인덱스를 사용하여 전체 리스트에서 일부를 잘라내어 반환한다.

슬라이싱 기본 문법 : 변수명[시작인덱스 : 마지막인덱스]

>>>rainbow = ['빨', '주', '노', '초', '파', '남', '보']
>>>rainbow[0:2]
['빨', '주']
#*마지막인덱스-1까지만 출력된다.
>>>rainbow[0:5]
['빨', '주', '노', '초', '파']
>>>rainbow[5:]
['남', '보']

 

3.3 리버스 인덱스

: 인덱스를 마지막값부터 시작하는 리버스 인덱스 : 기존 인덱스와 달리 마지막 값부터 -1을 할당하여 첫 번째 값까지 역순으로 올라오는 방식

['빨', '주', '노', '초', '파', '남', '보']
-7     -6    -5    -4    -3    -2    -1
>>>rainbow[-7:] #: -7 인덱스 값부터 끝까지 출력하라는 뜻.
['빨', '주', '노', '초', '파', '남', '보']

 

3.4 인덱스 범위를 넘어가는 슬라이싱

슬라이싱에서는 인덱스를 넘어서거나 입력하지 않더라도 자동으로 시작인덱스와 마지막 인덱스로 지정된다.

>>>print(rainbow[:]) #rainbow 변수의 처음부터 끝까지
['빨', '주', '노', '초', '파', '남', '보']

>>>print(rainbow[-50:50]) #범위 넘어갈 경우 자동으로 최대 범위 지정
['빨', '주', '노', '초', '파', '남', '보']

 

3.5 증가값

슬라이싱에서는 시작인덱스와 마지막인덱스 외 마지막 자리에 증가값을 넣을 수 있다.

변수명[시작인덱스 : 마지막인덱스 : 증가값]

>>>print(rainbow[::2]) #2칸 단위로
['빨', '노', '파', '보']
>>>print(rainbow[::-1]) #역으로 슬라이싱
['보', '남', '파', '초', '노', '주', '빨']

 

 

[4]리스트의 연산

4.1 덧셈 연산

>>>color1 = ['red', 'blue', 'green']
>>>color2 = ['orange', 'black', 'white']

>>>print(color1 + color2)
['red', 'blue', 'green', 'orange', 'black', 'white']

>>>print(len(color1))  #덧셈하고 나서도 color1 길이 여전히 3! 
3
#덧셈연산하더라도 어딘가 변수에 할당해주지 않으면 기존 변수에 변화 없음 

>>>total = color1 + color2 #리스트끼리는 자료연산_덧셈이 가능하다
>>>print(total)
['red', 'blue', 'green', 'orange', 'black', 'white']

 

4.2 곱셈 연산

: 기준리스트에 n을 곱했을 때, 같은 리스트를 n배만큼 늘려 준다.

#리스트 반복연산
>>>print(color1*2)  #color1 리스트 2회 반복
['red', 'blue', 'green', 'red', 'blue', 'green']

 

4.3 in 연산 ⇒ true/false

: 포함여부를 확인하는 연산. 하나의 값이 해당 리스트에 들어 있는 지 확인한다.

#포함여부 in, not in
>>>'blue' not in color2
True

 

 

[5]리스트의 추가 및 삭제

append(), extend(), insert(), remove(), del() : 기존 리스트 변경하는 연산.

5.1 append() : 맨 마지막 인덱스에 새로운 값 추가

#append 함수,   ['red', 'blue', 'green', 'white']
>>>color1 = ['red', 'blue', 'green']
>>>color1.append('white')
>>>color1
['red', 'blue', 'green', 'white']

 

5.2 extend() : 기존리스트에 새로운 리스트 합침(리스트 덧셈 연산) (값을 추가하는 것이 아니라 기존 리스트에 그대로 새로운 리스트 합침)

#extend 함수,   
>>>color1 = ['red', 'blue', 'green']
>>>color1.extend(['black','purple'])
>>>color1
['red', 'blue', 'green', 'black', 'purple']
#extend 함수2,   *['red', 'blue', 'green', 'p', 'u', 'r', 'p', 'l', 'e']
>>>color1 = ['red', 'blue', 'green']
>>>color1.extend('purple')
>>>color1
['red', 'blue', 'green', 'p', 'u', 'r', 'p', 'l', 'e']

 

5.3 insert() : 특정 위치에! 새로운 값 추가 (리스트 맨 끝에 값이 들어가는 것이 아니라 지정한 위치에 값이 들어간다)

#insert 함수,   ['orange', 'red', 'blue', 'green']
#0번째 인덱스값에 새로운 값'orange' 추가
>>>color1 = ['red', 'blue', 'green']
>>>color1.insert(0, 'orange')
>>>color1
['orange', 'red', 'blue', 'green']

 

5.4 remove() : 특정 값 지움. 삭제할 값을 remove()함수 안에 넣으면 리스트에 있는 해당 값이 삭제된다.

#remove 함수,   ['orange', 'blue', 'green']
>>>color1.remove('red')
>>>color1
['orange', 'blue', 'green']

 

5.5 del() : 특정 인덱스 값을 변경(재할당)하거나 삭제

#인덱스의 재할당과 삭제
>>>color1 = ['red', 'blue', 'green']
>>>color1[0] = 'orange'
>>>color1 #orange, blue, green
['orange', 'blue', 'green']

>>>del color1[0]
>>>color1
['blue', 'green']

 

[6] 패킹과 언패킹

: 리스트의 사용법 중 하나. 리스트에서만 사용하는 개념은 아니고 다른 시퀀스 자료형에서 일반적으로 사용할 수 있는 방법이다.

패킹 : 한 변수에 여러 개의 데이터를 할당하는 것. 리스트 그 자체를 뜻하기도 한다. 일반적으로 리스트보다 return()함수에서 좀 더 중요하게 쓰이는 개념이다.

언패킹 : 한 변수에 여러 개의 데이터가 들어있을 때 그것을 각각의 변수로 반환하는 방법이다.

>>> t = [1,2,3]      #1,2,3을 변수 t에 패킹
>>> a, b, c = t      #t에 있는 값 1,2,3 을 변수 a,b,c에 언패킹
>>> print(t, a, b, c)
[1,2,3] 1 2 3

 

*코드에 리스트 값이 3개인데 5개로 언패킹을 시도하면(언패킹 시 할당받는 변수의 개수가 적거나 많으면) 에러가 난다.

#패킹과 언패킹_에러
t = [1,2,3]
a,b,c,d,e = t #에러난다

 

[7] 이차원 리스트

리스트를 효율적으로 활용하기 위해 여러 개의 리스트를 하나의 변수에 할당하는 이차원리스트를 사용할 수 있다.

이차원리스트는 행렬과 같은 개념이다. 표의 칸에 값을 채웠을 때 생기는 값들의 집합이다.

국어 점수, 수학 점수, 영어 점수를 각각 하나의 리스트로 보고, 그 리스트에 있는 값들이 모두 하나의 리스트 변수에 할당 되면, 그것을 이차원리스트라 할 수 있다.

학생 A B C D E
국어 점수 49 79 20 100 80
수학 점수 6 7 8 9 10
영어 점수 49 79 48 60 100

 

이차원 리스트를 하나의 변수로 표현하기 위해서는 다음과 같이 코드를 작성하면 된다.

>>>kor_score = [49, 79, 20, 100, 80]
>>>math_score = [6, 7, 8, 9, 10]
>>>eng_score = [49, 79, 48, 60, 100]

>>>midterm_score = [kor_score, math_score, eng_score]
>>>midterm_score
[[49, 79, 20, 100, 80], [6, 7, 8, 9, 10], [49, 79, 48, 60, 100]]

>>>print(midterm_score)
[[49, 79, 20, 100, 80], [6, 7, 8, 9, 10], [49, 79, 48, 60, 100]]

#이차원리스트에 인덱싱하여 값에 접근하기 위해서는 다음 코드와 같이 대괄호 2개를 사용한다.
>>>print(midterm_score[0][2])
20
>>>print(midterm_score[2][2]) 
48

05. 리스트의 메모리 관리 방식

[1] 리스트의 메모리 저장

>>>midterm_score = [kor_score, math_score, eng_score]
>>>print(midterm_score)
[[49, 79, 20, 100, 80], [6, 7, 8, 9, 10], [49, 79, 48, 60, 100]]

>>>math_score[0]=1000
>>>print(midterm_score)
[[49, 79, 20, 100, 80], [1000, 7, 8, 9, 10], [11, 12, 48, 60, 100]]

math_score 값을 변경했는데 midterm_score 두 번째 행의 첫 번째 값이 변경되었다.

파이썬은 리스트를 저장할 때 값이 아니라, 값이 위치한 메모리 주소를 저장한다.

값과 메모리 주소 값의 차이를 설명하기 위한 코드다.

>>>a = 300
>>>b = 300

>>>a is b
False

>>>a==b
True

#== : 값을 비교하는 연산,  #is : 메모리 주소를 비교하는 연산

변수 a와 b의 메모리 주소에 값 300이 할당되어, 모두 300이라는 값을 갖고 있다.

==는 값을 비교하는 연산이기에 True지만, is는 메모리 주소를 비교하는 연산이기에 False다.

즉 a와 b는 값은 갖지만 메모리의 저장 주소는 다른 것이다.

>>>a = 1
>>>b = 1
>>>print(a is b)
True
>>>print(a == b)
True

이전 코드와 다르게 is와 == 연산자 모두 True를 반환한다.

(파이썬 인터프리터가 구동될 때 -5부터 256까지의 정수값을 특정 메모리 주소에 저장하는) 파이썬 정수형 저장 방식의 특성 때문에 주소와 값이 모두 같은 것으로 나온다.

 

리스트는 기본적으로 값을 연속으로 저장하는 것이 아니라, 값이 있는 주소를 저장하는 방식이다.

제일 처음 나온 코드에서 midterm_score 변수의 경우 : 각각의 값이 아닌 math_score의 메모리주소를 가지고 있었는데,

math_score의 값이 변하니 midterm score 내부에 있는 값도 변하는 것이다.

 

+

파이썬에서 리스트는 변경 가능한(mutable)객체다. 리스트를 다른 변수에 할당하면, 그 변수는 리스트의 주소를 참조한다.

그래서 예제에서 **midterm_score**는 kor_score, math_score, eng_score 리스트들의 주소를 가지고 있는 것이다.

**math_score[0]=1000**을 수행하면, math_score 리스트의 첫 번째 값이 1000으로 변경되고, midterm_score 리스트 내의 **math_score**의 주소가 참조하는 실제 리스트가 변경되는 것이기 때문에, **midterm_score**에 반영되는 것이다.

리스트들의 메모리 주소가 같기 때문에 하나를 변경하면 다른 변수에서도 그 변경이 반영된다.

 

[2] 메모리 저장 구조로 인한 리스트의 특징

2.1 특징1) 하나의 리스트에 다양한 자료형 포함 가능

>>>a = ["color", 1, 0.2]  #하나의 리스트에 다양한 자료형 가능
>>>color = ['red','blue']
>>>a[0] = color           #리스트 안에 리스트 입력 가능, "color"문자열 대신 color리스트 넣으라는 뜻
>>>print(a)
[['red', 'blue'], 1, 0.2]

파이썬의 리스트 값이 메모리 주소를 저장해 메모리에 새로운 값을 할당하는 데 있어 매우 높은 자유도 보장하므로 이와 같은 중첩리스트를 만들 수 있다. (c와 자바같은 언어와 다른 파이썬 특징)

 

 

2.2 특징2) 리스트의 저장 방식

>>>a = [5,4,3,2,1]
>>>b = [1,2,3,4,5]
>>>b = a
>>>print(b)
[5,4,3,2,1]
#a만 정렬하고 b를 출력하면?
>>>a.sort()
>>>print(b)
[1,2,3,4,5]

a를 정렬했는데 b도 정렬되었다.

b=a를 입력하는 순간, b리스트도 a리스트의 메모리주소와 같이 연결되기 때문이다. (같은 메모리 주소를 가리키게 된다)

두 변수가 같은 메모리 주소와 연결되어있으므로, 하나의 변수값만 바뀌어도 둘 다 영향을 받는다.

#b에 새로운 값을 할당하면?
>>>b = [6,7,8,9,10]
>>>print(a,b)
[1, 2, 3, 4, 5] [6, 7, 8, 9, 10]

b에 새로운 값을 할당하면 a와 b는 같은 메모리주소가 연결되지 않는다.

즉, b는 새로운 메모리 주소에 새로운 값을 할당할 수 있는 것이다.

b=a코드를 기억해야 한다. 어떤 리스크 값을 하나의 변수에 할당하는 순간, 두 변수는 같은 메모리 주소에 연결되는 것이다.

a --> [5,4,3,2,1] <-- 메모리 주소: 0x001
b --> [1,2,3,4,5] <-- 메모리 주소: 0x002


b = a
a --> [5,4,3,2,1] <-- 메모리 주소: 0x001
                \
b ---------------> [5,4,3,2,1] <-- 메모리 주소: 0x001
(a와 b가 동일한 메모리 주소를 가리키게 됨)


a.sort() 수행 후:
a --> [1,2,3,4,5] <-- 메모리 주소: 0x001
                \
b ---------------> [1,2,3,4,5] <-- 메모리 주소: 0x001
(b도 같은 주소를 참조하므로 정렬된 결과가 반영됨)


b = [6,7,8,9,10]

a --> [1,2,3,4,5] <-- 메모리 주소: 0x001
b --> [6,7,8,9,10] <-- 메모리 주소: 0x003
(b에 새로운 리스트를 할당하면 b는 새로운 메모리 주소를 참조하게 됨)

 

 

출처 : 최성철, 『IT CookBook, 데이터 과학을 위한 파이썬 프로그래밍(2판)』, 한빛미디어(2023)