06-4 ~ 07-1 (p.278 ~ p.292)

 

어제부터 시작한 6장을 모두 끝내고 7장의 '정규표현식'을 배우기 시작했는데, 필자의 말로는 정규표현식은 현직자들도 잘 모를 수 있는 고급 주제라서 가벼운 마음으로 읽어달라고 했다. 하지만 책에도 소개되어 있고 이해하면 매우 유용하게 사용할 수 있다고 하니 어렵더라도 최대한 이해하려고 노력해봐야겠다!

 

유용한데 안배우는건 못참지 ㅋㅋ

 


 

06-4 간단한 메모장 만들기

 

문제 : 원하는 메모를 파일에 저장하고 추가 및 조회가 가능한 메모장을 만들어라.

 

필요한 기능은? : 메모 추가하기, 메모 조회하기
입력받는 값은? : 메모 내용, 프로그램 실행 옵션

출력하는 값은? : memo.txt

1. 우선 다음과 같이 입력으로 받은 옵션과 메모를 출력하는 코드를 작성한다.

# C:/doit/memo.py
import sys

option = sys.argv[1] # sys.argv : 프로그램을 실행할 때 입력된 값을 읽어 들임
                     # sys.argv[0]은 프로그램 이름인 memo.py이므로 [1]부터 시작
memo = sys.argv[2]

print(option)
print(memo)

 

2. memo.py를 작성했다면 다음 명령을 수행해 본다.

# cmd
C:\doit>python memo.py -a "Life is too short"
-a
Life is too short

 

3. 이제 입력으로 받은 메모를 파일에 쓰도록 코드를 변경해 본다.

# C:/doit/memo.py
import sys

option = sys.argv[1]

if option == '-a': # 옵션이 -a인 경우에만 memo 값을 읽고 memo.txt 파일에 그 값을 씀
    memo = sys.argv[2]
    f = open('memo.txt', 'a')
    f.write(memo)
    f.write('\n')
    f.close()

 

4. 이제 다음과 같은 명령을 수행해 본다.

# cmd
C:\doit>python memo.py -a "Life is too short"
C:\doit>python memo.py -a "You need python"

# 결과
C:\doit>type memo.txt
Life is too short
You need python

 

5. 이번에는 작성한 메모를 출력하는 부분을 만들 차례이다.

# C:/doit/memo.py
import sys

option = sys.argv[1]

if option == '-a':
    memo = sys.argv[2]
    f = open('memo.txt', 'a')
    f.write(memo)
    f.write('\n')
    f.close()
elif option == '-v': # -v : 메모 출력 옵션
    f = open('memo.txt')
    memo = f.read()
    f.close()
    print(memo)
# 결과
C:\doit>python memo.py -v
Life is too short
You need python

 

06-5 탭을 4개의 공백으로 바꾸기

 

문제 : 문서 파일을 읽어서 그 문서 파일 안에 있는 탭(tab)을 공백(space) 4개로 바꾸어 주는 스크립트를 작성해라.

 

필요한 기능은? : 문서 파일 읽어 들이기, 문자열 변경하기
입력받는 값은? : 탭을 포함한 문서 파일

출력하는 값은? : 탭이 공백으로 수정된 문서 파일
# 다음과 같은 형식으로 프로그램 수행
python tabto4.py src dst
# src : 탭을 포함하고 있는 원본 파일 이름
# dst : 파일 안의 탭을 공백 4개로 변환한 결과를 저장할 파일 이름

1. 우선 다음과 같이 tabto4.py 파일을 작성한다.

# C:/doit/tabto4.py
# sys.argv를 사용하여 입력값을 확인하도록 한 코드
import sys

src = sys.argv[1]
dst = sys.argv[2]

print(src)
print(dst)

 

2. 다음과 같이 수행했을 입력값이 정상적으로 출력되는지 확인해 본다.

# cmd
C:\doit>python tabto4.py a.txt b.txt
a.txt
b.txt

 

3. 테스트를 위한 원본 파일(탭을 포함하는 파일)인 a.txt를 다음과 같이 작성한다. 각 단어는 탭(\t) 문자로 분리되도록 입력해야 한다.

Life    is         too         short
You    need    python

 

4. 테스트를 위한 원본 파일(탭을 포함하는 파일)인 a.txt를 다음과 같이 작성한다. 각 단어는 탭(\t) 문자로 분리되도록 입력해야 한다.

# C:/doit/tabto4.py
import sys

src = sys.argv[1]
dst = sys.argv[2]

f = open(src)
tab_content = f.read()
f.close()

space_content = tab_content.replace("\t", " "*4) # replace 함수를 사용해서 탭을 4개의 공백으로 변경
print(space_content)

 

5. tabto4.py를 위와 같이 변경한 후 다음과 같은 명령을 수행해 본다.

# cmd
C:\doit>python tabto4.py a.txt b.txt
Life  is  too  short
You   need   python
# 탭 문자가 공백 4개로 변경되어 출력

 

6. 이제 변경된 내용을 b.txt. 파일에 저장할 수 있도록 다음과 같이 프로그램을 변경해 본다.

# C:/doit/tabto4.py
import sys

src = sys.argv[1]
dst = sys.argv[2]

f = open(src)
tab_content = f.read()
f.close()
space_content = tab_content.replace("\t", " "*4)

f = open(dst, 'w') # 탭이 공백으로 변경된 space_content를 출력 파일인 dst에 쓰도록 함
f.write(space_content)
f.close()

 

7. 프로그램을 실행하기 위해 다음 명령을 수행한다.

# cmd
C:\doit>python tabto4.py a.txt b.txt
# 결과 : C:\doit 디렉터리에 b.txt 파일 생성

 

06-6 하위 디렉터리 검색하기

 

문제 : 특정 디렉터리부터 시작해서 그 하위 모든 파일 중 파이썬 파일(*.py)만 출력해 주는 프로그램을 만들어라.

 

1. 다음과 같이 sub_dir_search.py 파일을 작성해 본다.

# C:/doit/sub_dir_search.py

def search(dirname):
    print(dirname)
    
search("C:/")
# search 함수를 만들고 시작 디렉터리를 입력받도록 코드 작성

 

2. 이제 이 디렉터리에 있는 파일을 검색할 수 있도록 소스를 변경해 본다.

# C:/doit/sub_dir_search.py
import os

def search(dirname):
    filenames = os.listdir(dirname) # os.listdir : 디렉터리에 있는 파일들의 리스트 구해줌
    for filename in filenames:
        full_filname = os.path.join(dirname, filename) # 디렉터리를 포함한 전체 경로를 구해주는 함수
        print(full_filename)
        
search("C:/")

# 결과 : C:/ 디렉터리에 있는 파일 목록 출력

 

3. 이제 C:/ 디렉터리에 있는 파일들 중 확장자가 .py인 파일만을 출력하도록 코드를 변경해 본다.

# C:/doit/sub_dir_search.py
import os

def search(dirname):
    filenames = os.listdir(dirname)
    for filename in filenames:
        full_filname = os.path.join(dirname, filename)
        ext = os.path.splitext(full_filname)[-1] # 파일 이름에서 확장자만 추출하기 위해 함수 사용
                                                 # 파일 이름을 확장자를 기준으로 두 부분으로 나눔
        if ext == '.py':
            print(full_filname)
        
search("C:/")

 

4. 하지만 우리가 원하는 것은 C:/디렉터리 바로 밑에 있는 파일뿐만 아니라 그 하위 디렉터리(sub directory)를 포함한 모든 파이썬 파일을 검색하는 것이다. 하위 디렉터리도 검색이 가능하도록 다음과 같이 코드를 변경해야 한다.

# C:/doit/sub_dir_search.py
import os

def search(dirname):
    try: # os.listdir를 수행할 때 권한이 없는 디렉터리에 접근하더라도 프로그램이 오류로 종료되지 않고 그냥 수행토록 하기 위해 사용
        filenames = os.listdir(dirname)
        for filename in filenames:
            full_filname = os.path.join(dirname, filename)
            if os.path.isdir(full_filname): # full_filename이 디렉터리인지 파일인지 구별하기 위해 함수 사용
                search(full_filname) # 디렉터리일 경우 해당 경로를 입력받아 다시 search 함수 호출(재귀 호출)
            else:
                ext = os.path.splitext(full_filname)[-1]
                if ext == '.py':
                    print(full_filname)
    except PermissionError:
        pass
        
search("C:/")

* 하위 디렉터리 검색을 쉽게 해주는 os.walk

import os

for (path, dir, files) in os.walk("C:/"):
    for filename in files:
        ext = os.path.splitext(filename)[-1]
        if ext == '.py':
            print("%s/%s" % (path, filename))
# os.walk : 시작 디렉터리부터 시작하여 그 하위 모든 디렉터리를 차례대로 방문하게 해주는 함수

 

 

7장 : 정규 표현식

 

7장에서는 정규 표현식을 배운다.

 

07-1 정규 표현식 살펴보기

 

정규 표현식(Regular Expressions)은 복잡한 문자열을 처리할 때 사용하는 기법으로, 파이썬만의 고유 문법이 아니라 문자열을 처리하는 모든 곳에서 사용한다. 정규 표현식을 배우는 것은 파이썬을 배우는 것과는 또 다른 영역이다.

 

정규 표현식은 왜 필요한가?

주민등록번호를 포함하고 있는 텍스트가 있다. 이 텍스트에 포함된 모든 주민등록번호의 뒷자리를 * 문자로 변경해 보자.

이 문제를 정규식을 모른다면 다음과 같은 순서로 프로그램을 작성해야 할 것이다.

1. 전체 텍스트를 공백 문자로 나눈다(split).
2. 나뉜 단어가 주민등록번호 형식인지 조사한다.
3. 단어가 주민등록번호 형식이라면 뒷자리를 *로 변환한다.
4. 나뉜 단어를 다시 조립한다.

이를 구현한 코드는 다음과 같다.

data = """
park 800905-1049118
kim  700905-1059119
"""

result = []
for line in data.split("\n"):
    word_result = []
    for word in line.split(" "):
        if len(word) == 14 and word[:6].isdigit() and word[7:].isdigit():
            word = word[:6] + "-" + "*******"
        word_result.append(word)
    result.append(" ".join(word_result))
print("\n".join(result))

# 결과
park 800905-*******
kin 700905-*******

하지만 정규식을 사용하면 다음처럼 훨씬 간편하고 직관적으로 코드를 작성할 수 있다.

import re # 정규 표현식을 사용하기 위한 모듈

data = """
park 800905-1049118
kim  799905-1059119
"""

pat = re.compile("(\d{6})[-]\d{7}")
print(pat.sub("\g<1>-*******", data))

# 결과
park 800905-*******
kin 700905-*******

* 정규 표현식을 사용하면 간단한 예제에서도 코드가 상당히 간결해진다. 만약 찾으려는 문자열 또는 바꾸어야 할 문자열의 규칙이 매우 복잡하다면 정규식의 효용은 더 커지게 된다.

 

첫째 마당 복습 ~ 06-3 (p.266 ~ p.277)

 

드디어 첫째 마당을 끝내고 둘째 마당에 돌입했다. 이 책의 여정도 거의 끝나간다.

문법을 다 배우고 이제 프로그램을 어떻게 작성해야 할지 막막했는데, 둘째 마당에서는 이러한 독자들의 고충을 잘 이해하고 프로그램 작성 방식을 차근차근 알려준다. 다시 생각해도 이 책으로 사길 잘한 것 같다!

 

잘했어 과거의 나!

 


 

6장 : 파이썬 프로그래밍, 어떻게 시작해야 할까?

 

6장에서는 짤막한 스크립트(에디터로 작성한 파이썬 프로그램 파일)와 함수를 만들어 보면서 프로그래밍 감각을 키운다.

 

06-1 내가 프로그램을 만들 수 있을까?

 

문법을 어느 정도 익혔지만 프로그램을 작성하는 것에 자신이 없다면 다른 사람들이 만든 프로그램 파일을 자세히 들여다보도 분석하는 것이 좋다. 그러다 보면 자신만의 새로운 아이디어가 떠오를 수도 있다.

하지만 여기에서 가장 중요한 것은 자신의 수준에 맞는 소스를 찾는 것이다.

처음에는 구구단 프로그램을 작성해 보자.

* 프로그램을 만들려면 가장 먼저 '입력'과 '출력'을 생각하라.

 

구구단 프로그램
함수 이름은? : GuGu
입력받는 값은? : 2
출력하는 값은? : 2단(2, 4, 6, 8, ..., 18)
결과는 어떤 형태로 저장? : 연속된 자료형이므로 리스트

 

1. 먼저 이렇게 입력한다. GuGu라는 함수에 2를 입력값으로 주면 result라는 변수에 결괏값을 넣으라는 뜻이다.

result = GuGu(2)

 

 

2. 이제 결괏값을 어떤 형태로 받을 것인지 고민해 본다. 2단이니까 2, 4, 6, ..., 18까지 갈 것이다.

이런 종류의 데이터는 리스트 자료형이 딱이다. 따라서 result = [2, 4, 6, ..., 18] 같은 결과를 얻는 것이 좋겠다는 생각을 먼저 하고 나서 프로그래밍을 시작하는 것이 필요하다.

 

3. 어떻게 만들지 생각해 봤으니 1번에서 입력한 문장은 지우고 진짜 프로그램을 짜 보자. 일단 이름을 GuGu로 지은 함수를 다음과 같이 만든다.

def GuGu(n):
    print(n) # 실행하면 2를 출력

 

4. 이제 결괏값을 담을 리스트를 하나 생성하자. 앞에서 작성한 print(n)은 입력이 잘되는지를 확인하기 위한 것이므로 지워도 좋다.

def GuGu(n):
    result = []

 

5. 다음으로 result에 2, 4, 6, ..., 18을 어떻게 넣어야 할지 생각해보자.

def GuGu(n):
    result = []
    result.append(n*1) # append 내장 함수 사용
    result.append(n*2)
    result.append(n*3)
    result.append(n*4)
    result.append(n*5)
    result.append(n*6)
    result.append(n*7)
    result.append(n*8)
    result.append(n*9)
    return result
print(GuGu(2))
>>> [2, 4, 6, 8, 10, 12, 14, 16, 18]

 

6. 하지만 위 함수는 반복이 너무 많다. 가만 보면 result.append(n*'숫자')의 '숫자' 위치에 1부터 9까지 숫자만 다르게 들어가 있다는 것을 알 수 있다. 똑같은 일을 반복할 때는 '반복문'을 사용한다고 했다. 그렇다면 1부터 9까지 출력해 주는 반복문을 만들면 되지 않을까?

def GuGu(n):
    result = [] # 결괏값을 저장할 리스트 result
    i = 1
    while i < 10:
        result.append(n * i)
        i = i + 1
    return result
    
print(GuGu(2))
>>> [2, 4, 6, 8, 10, 12, 14, 16, 18]

* 프로그래밍을 할 땐 매우 구체적으로 접근해야 머리가 덜 아프다.

 

06-2 3과 5의 배수 합하기

 

문제 : 10 미만의 자연수에서 3과 5의 배수를 구하면 3, 5, 6, 9이다. 이들의 총합은 23이다. 1000 미만의 자연수에서 3의 배수와 5의 배수의 총합을 구하라.

 

입력하는 값은? : 1부터 999까지(1000미만의 자연수)
출력하는 값은? : 3의 배수와 5의 배수의 총합
생각해 볼 것은? : 1. 3의 배수와 5의 배수는 어떻게 찾지?
                                        2. 3의 배수와 5의 배수가 겹칠 때는 어떻게 하지?

 

1. 먼저 1000 미만의 자연수는 어떻게 구할 수 있을지 생각해 보자. 다음과 같이 변수에 초깃값 1을 준 후 루프를 돌리며 1씩 증가시켜서 999까지 진행하는 방법이 가장 일반적인 방법일 것이다.

n = 1
while n < 1000:
    print(n)
    n += 1

또는 다음과 같이 좀 더 파이썬다운 range 함수를 사용할 수도 있다.

for n in range(1, 1000):
    print(n)

 

2. 1000까지의 자연수를 차례로 구하는 방법을 알았으니 3과 5의 배수를 구하는 방법을 알아보자.

1부터 1000까지의 수 중 3으로 나누었을 때 나누어 떨어지는 경우, 즉 3으로 나누었을 때 나머지가 0인 경우가 바로 3의 배수이다.

for n in range(1, 1000):
    if n % 3 == 0:
        print(n)
# 5의 배수도 동일한 방법으로 작성

 

3. 이러한 내용을 바탕으로 최종 작성하면 다음과 같다.

result = 0
for n in range(1, 1000): # 1부터 999까지 n에 대입하며 반복
    if n % 3 == 0 or n % 5 == 0: # n을 3으로 나눈 나머지가 0이거나 n을 5로 나눈 나머지가 0이라면
        result += n
print(result)

이 문제에는 한 가지 함정이 있는데 3으로도 5로도 나누어지는 15와 같은 수를 이중으로 더해서는 안 된다는 점이다.

따라서 15와 같이 3의 배수도 되고 5의 배수도 되는 값이 이중으로 더해지지 않기 위해 or 연산자를 사용하였다.

 

06-3 게시판 페이징하기

 

문제 : 게시물의 총 건수와 한 페이지에 보여 줄 게시물 수를 입력으로 주었을 때 총 페이지 수를 출력하는 프로그램을 작성하라.

 

함수의 이름은? : getTotalPage
입력받는 값은? : 게시물의 총 건수(m), 한 페이지에 보여 줄 게시물 수(n)

출력하는 값은? : 총 페이지 수

 

1. 총 건수(m)를 한 페이지에 보여 줄 게시물 수(n)로 나누고 1을 더하면 총 페이지 수를 얻을 수 있다.

총 페이지 수 = (총 건수 / 한 페이지당 보여 줄 건수) + 1

 

2. 이러한 공식을 적용했을 경우 총 페이지 수가 표의 값처럼 구해지는지 확인해 보자(m을 n으로 나눌 때 소수점 아래 자리를 버리기 위해 / 대신 // 연산자 사용)

def getTotalPage(m, n):
    return m // n + 1
    
print(getTotalPage(5, 10)) # 1이 출력
print(getTotalPage(15, 10)) # 2가 출력
print(getTotalPage(25, 10)) # 3이 출력
print(getTotalPage(30, 10)) # 3이 출력되어야 하는데 4가 출력

 

3. 실패 케이스는 총 게시물 수와 한 페이지에 보여 줄 게시물 수를 나눈 나머지 값이 0이 될 때 발생함을 유추할 수 있을 것이다. 이 실패 케이스를 해결하려면 다음과 같이 코드를 변경해야 한다.

def getTotalPage(m, n):
    if m % n == 0:
        return m // n # 나누었을 때 나머지가 0인 경우는 몫만 돌려줌
    else:
        return m // n + 1

print(getTotalPage(5, 10))
print(getTotalPage(15, 10))
print(getTotalPage(25, 10))
print(getTotalPage(30, 10))

 

05-6 ~ 05장 연습문제 (p.247 ~ p.265)

 

슬슬 기본 문법은 마무리되고 응용 부분 공부를 시작하니 머리를 더 쓰면서 공부를 해야 하지만 전보다 더 재미있어지는 것 같다. 본격적으로 프로그램을 작성해 보기 전 단계를 밟고 있는 느낌이다.

이대로 쭉 흥미를 잃지 말고 전진하자아~~

 

흥 미 진 진

 


 

05-6 라이브러리

 

라이브러리는 말 그대로 원하는 정보를 찾아보는 곳이다. 전 세계의 파이썬 사용자들이 만든 유용한 프로그램을 모아 놓은 것이다. (파이썬 라이브러리는 파이썬을 설치할 때 자동으로 컴퓨터에 설치한다.)

밑에 적는 것은 자주 사용되고 꼭 알아 두면 좋은 라이브러리들이다.

 

sys

sys 모듈은 파이썬 인터프리터가 제공하는 변수와 함수를 직접 제어할 수 있게 해주는 모듈이다.

# 명령 행에서 인수 전달하기 - sys.argv
# 명령 프롬프트 창에서 모듈명 뒤에 또 다른 값을 함께 넣어 주면 sys.argv 리스트에 그 값 추가
#argv_test.py
import sys
print(sys.argv)

# cmd
C:/doit/Mymod>python argv_test.py you need python
['argv_test.py', 'you', 'need', 'python']


# 강제로 스크립트 종료하기 - sys.exit
# Ctrl + z처럼 대화형 인터프리터를 종료하는 것과 같은 기능
>>> sys.exit()


# 자신이 만든 모듈 불러와 사용하기 - sys.path
# 파이썬 모듈들이 저장되어 있는 위치 나타냄
# 이 위치에 있는 파이썬 모듈은 경로에 상관없이 어디에서나 불러올 수 있음
import sys
sys.path
>>> ['', 'C:\\Windows\\SYSTEM32\\python37.zip...'] # ''는 현재 디렉터리

# path_append.py # sys.path.append를 사용해 경로 이름 추가
import sys
sys.path.append("C:/doit/Mymod")

 

pickle

pickle은 객체의 형태를 그대로 유지하면서 파일에 저장하고 불러올 수 있게 하는 모듈이다.

import pickle
f = open("test.txt", 'wb')
data = {1: 'python', 2: 'you need'}
pickle.dump(data, f)
f.close()
# dump 함수 사용해서 딕셔너리 객체인 data를 그대로 파일에 저장

import pickle
f = open("test.txt", 'rb')
data = pickle.load(f)
print(data)
>>> {1:'python', 2:'you need'}
# pickle.dump로 저장한 파일을 pickle.load를 사용해 원래 있던 딕셔너리 객체(data) 상태 그대로 불러옴

 

OS

OS 모듈은 환경 변수나 디렉터리, 파일 등의 OS 자원을 제어할 수 있게 해주는 모듈이다.

# 내 시스템의 환경 변수 값을 알고 싶을 때 - os.environ
import os
os.environ
>>> environ({'PROGRAMFILES': 'C:\\Program Files', 'APPDATA': ... 생략 ...})
# 환경 변수 값은 컴퓨터 마다 다름

os.environ['PATH'] # PATH 환경 변수 내용
>>> 'C:\\ProgramData\\Oracle\\Java\\javascript; ... 생략 ...'


# 디렉터리 위히 변경하기 - os.chdir
os.chdir("C:\WINDOWS")


# 디렉터리 위치 돌려받기 - os.getcwd
os.getcwd()
>>> 'C:\\WINDOWS' # 현재 디렉터리 위치에 따라 결과가 다를 수 있음


# 시스템 명령어 호출하기 - os.system
os.system("dir")


# 실행한 시스템 명령어 결괏값 돌려받기 - os.popen
# 실행한 결괏값을 읽기 모드 형태의 파일 객체로 돌려줌
f = os.popen("dir")
print(f.read()) # 읽어 들인 파일 객체의 내용 보기


# 기타 유용한 os 관련 함수
os.mkdir(디렉터리) # 디렉터리를 생성
os.rmdir(디렉터리) # 디렉터리 삭제(단 디렉터리가 비어 있어야 함)
os.unlink(파일 이름) # 파일을 지움
os.rename(src, dst) # src라는 이름의 파일을 dst라는 이름으로 변경

 

shutil

shutil은 파일을 복사해 주는 파이썬 모듈이다.

import shutil
shutil.copy("src.txt", "dst.txt") # src라는 이름의 파일을 dst로 복사
# dst가 디렉터리 이름이면 src라는 파일 이름으로 복사
# dst 디렉터리에 복사하고 동일한 파일 이름이 있으면 덮어씀

 

glob

특정 디렉터리에 있는 파일 이름 모두를 알려준다.

*, ? 등 메타 문자를 써서 원하는 파일만 읽어 들일 수도 있다.

# 디렉터리에 있는 파일들을 리스트로 만들기 - glob(pathname)
import glob
glob.glob("C:/doit/mark*") # mark로 시작하는 파일을 모두 찾음(* 사용)
>>> ['C:/doit\\marks1.py', 'C:/doit\\marks2.py', 'C:/doit\\marks3.py']

 

tempfile

파일을 임시로 만들어서 사용할 때 유용한 모듈이다.

import tempfile
filename = tempfile.mkstemp() # 중복되지 않는 임시 파일의 이름을 무작위로 생성
filename
>>> 'C:\WINDOWS\TEMP\~-275151-0'

import tempfile
f = tempfile.TemporaryFile() # 임시 저장 공간으로 사용할 파일 객체를 돌려줌
                             # 기본적으로 바이너리 쓰기 모드(wb)를 가짐
f.close() # 생성한 임시 파일이 자동으로 삭제됨

 

time

시간과 관련된 모듈이다.

# time.time - 현재 시간을 수 형태로 돌려주는 함수
import time
time.time()
>>> 988348015.73417199


# time.localtime - time.time()이 돌려준 실수 값을 사용해서 연도, 월, 일, 시, 분, 초, ... 형태로 변환
# import time
time.localtime(time.time())
>>> time.stuct_time(tm_year=2013, tm_mon=5, tm_mday21, ...)


# time.asctime - time.localtime에 의해서 반환된 튜플 형태의 값을 인수로 받아서 날짜와 시간을 알아보기 쉬운 형태로 돌려줌
time.asctime(time.localtime(time.time()))
>>> 'Sat Apr 28 20:50:20 2001'


# time.ctime - 위 함수를 간편하게 표시, 항상 형재 시간만을 돌려줌
time.ctime()
'Sat Apr 28 20:56:31 2001'


# time.strftime
time.strftime(' 출력할 형식 포맷 코드', time.localtime(time.time()))
# strftime 함수는 시간에 관계된 것을 세밀하게 표현하는 여러 가지 포맷 코드 제공
import time
time.strftime('%x', time.localtime(time.time()))
>>> '05/01/01'


# time.sleep - 일정한 시간 간격을 두고 루프 실행 가능(주로 루프 안에서 사용)
import time
for i in range(10):
    print(i)
    time.sleep(1) # 1초 간격으로 0부터 9까지의 숫자 출력

 

calendar

파이썬에서 달력을 볼 수 있게 해주는 모듈이다.

# calendar.calendar(연도, 월) - 해당 월 달력을 보여줌, 월 생략하면 연도 전체를 보여줌
import calendar
print(calendar.calendar(2022))


# calendar.prcal(연도) - 위와 똑같은 결괏값
calendar.prcal(2022)


# calendar.weekday(연도, 월, 일) - 그 날짜에 해당하는 요일 정보를 보여줌
calendar.weekday(2022, 2, 15)
>>> 1 # 월요일부터 0, 화요일 1, 수요일 2... 순서


# calendar.monthrange(연도, 월) - 입력받은 달의 1일이 무슨 요일인지, 그 달이 며칠까지 있는지 튜플 형태로 보여줌
calendar.monthrange(2022, 2)
>>> (1, 28)

 

random

난수(규칙이 없는 임의의 수)를 발생시키는 모듈이다.

import random
random.random() # 0.0 ~ 1.0 사이의 실수 중에서 난수 값을 돌려줌
>>> 0.5345324654543467

random.randint(1, 10) # 1 ~ 10 사이의 정수 중에서 난수 값을 돌려줌
>>> 7


# random.shuffle - 리스트의 항목을 무작위로 섞음
import random
data = [1, 2, 3, 4, 5]
random.shuffle(data)
data
>>> [5, 1, 3, 4, 2]

 

webbrowser

자신의 시스템에서 사용하는 기본 웹 브라우저를 자동으로 실행하는 모듈이다.

import webbrowser
webbrowser.open("http://google.com")

webbrowser_new.open("http://google.com") # 웹브라우저가 이미 실행된 상태라도 새로운 창으로 열림

 

threading

한 프로세스 안에서 2가지 또는 그 이상의 일을 동시에 수행할 수 있게 해주는 모듈이다.

# thread_test.py
import time
import threading # threading 모듈 import

def long_task(): # 5초의 시간이 걸리는 함수
    for i in range(5):
        time.sleep(1) # 1초 간격으로 실행
        print("working:%s\n" % i)
        
print("Start")

threads = []
for i in range(5): # long_task를 5회 수행
    t = threading.Thread(target=long_task) # 스레드 생성
    threads.append(t)
for t in threads:
    t.start() # 스레드 실행
for t in threads:
    t.join() # join으로 스레드가 종료될 때까지 기다림
    
print("End")
>>> Start
    working:0 # long_task가 동시에 5번씩 실행
    working:0
    working:0
    working:0
    working:0
    
    working:1
    working:1
    working:1
    working:1
    working:1
    .
    .
    .
    working:4
    working:4
    working:4
    working:4
    working:4
    End

 

05-4 ~ 05-5 (p.222 ~ p.246)

 

어느덧 10일 차로 절반 이상을 달려왔다.

10일 동안 교재의 3분에 2 이상을 공부하다 보니 앞에서 배웠던 부분들을 들춰가면서 공부를 하게 된다.

이 교재를 다 보더라도 틈틈이 복습을 해야겠다. 그래도 지금까지 배운 것들이 있다 보니 처음보다는 수준이 오른 것이 느껴진다..!

 

미약하지만 이런 느낌

 


 

05-4 예외처리

 

파이썬은 try, except를 사용해서 예외적으로 오류를 처리할 수 있게 해 준다.

 

오류 예외 처리 기법

try, except문

# try, except문의 기본 구조
try:
   ...
except [발생오류[as 오류 메시지 변수]]: # []는 괄호 안의 내용을 생략할 수 있다는 관례 표현 기법
   ...
# 1. try, except만 쓰는 방법
# 오류 종류에 상관없이 오류가 발생하면 except 블록 수행
try:
    4 / 0
except:
    print("오류 발생")
>>> 오류 발생


# 2. 발생 오류만 포함한 except문
# 오류가 발생했을 때 except에 미리 정해 놓은 오류 이름과 일치할 때만 except 블록을 수행
try:
    4 / 0
except ZeroDivisionError: # except 발생 오류:
    print("오류 발생")
>>> 오류 발생


# 3. 발생 오류와 오류 메시지 변수까지 포함한 except문
# 두 번째 경우에서 오류 메시지의 내용까지 알고 싶을 때 사용
try:
    4 / 0
except ZeroDivisionError as e: # except 발생 오류 as 오류 메시지 변수:
    print(e)
>>> division by zero

 

try... finally

finally 절은 try문 수행 도중 예외 발생 여부에 상관없이 항상 수행된다. 보통 사용한 리소스를 close 해야 할 때에 많이 사용된다.

f = open('foo.txt', 'w')
try:
    f .write("Hello") # 무언가를 수행한다.
finally:
    f.close()
# foo.txt 파일을 쓰기 모드로 연 후, try문을 수행하고 예외 발생 여부와 상관없이 finally절 수행

 

여러 개의 오류 처리하기

try:
    a = [1, 2]
    print(a[3])
    4 / 0
except ZeroDivisionError:
    print("0으로 나눌 수 없습니다.")
except IndexError:
    print("인덱싱할 수 없습니다.")
>>> 인덱싱할 수 없습니다. # 인덱싱 오류가 먼저 발생했으므로 ZeroDivisionError 오류는 발생하지 않음

# 두 오류를 함께 처리도 가능
try:
    a = [1, 2]
    print(a[3])
    4 / 0
except (ZeroDivisionError, IndexError) as e:
    print(e)

 

 

오류 회피하기

try:
    f = open("나없는파일", 'r')
except FileNotFoundError:
    pass # 파일이 없더라도 오류를 발생시키지 않고 통과한다.

 

오류 일부러 발생시키기

파이썬은 raise 명령어를 사용해 오류를 강제로 발생시킬 수 있다.

class Bird:
    def fly(self):
        raise NotImplementedError # 꼭 작성해야 하는 부분이 구현되지 않았을 경우 일부러 오류를 일으키기 위해 사용하는 내장 오류
         
class Eagle(Bird): # Eagle 클래스는 Bird 클래스를 상속 받음
        pass # Eagle 클래스에서 fly 함수를 구현하지 않았기 때문에 Bird 클래스의 fly 함수 호출
             # Bird 클래스의 fly 함수에 있는 raise문에 의해 NotImplementedError 오류 발생

eagle = Eagle()
eagle.fly()
>>> NotImplementedError 오류 발생

# 오류가 발생되지 않게 하려면 Eagle 클래스에 fly 함수를 반드시 구현해야 함
class Eagle(Bird):
    def fly(self):
        print("vert fast")

eagle = Eagle()
eagle.fly()
>>> very fast

 

예외 만들기

예외는 파이썬 내장 클래스인 Exception 클래스를 상속하여 만들 수 있다.

class MyError(Exception):
    def __str__(self):
        return "허용되지 않는 별명입니다."

def say_nick(nick):
    if nick == '바보':
        raise MyError()
    print(nick)
    
try:
    say_nick("천사")
    say_nick("바보")
except MyError as e:
    print(e) # 오류 메시지를 출력했을 때 오류 메시지가 보이게 하려면 오류 클래스에 __str__ 메서드 구현해야 함

 

05-5 파이썬 내장 함수

 

# 앞에서 살펴본 함수들은 생략
# abs : 어떤 숫자를 입력받았을 때, 절댓값을 돌려줌
abs(3) 
>>> 3

# all : 인수에 반복 가능한 자료형을 받고 모두 참이면 True, 거짓이 하나라도 있으면 Fals 반환
all([1, 2, 3])
>>> True
all([1, 2, 3, 0])
>>> False

# any : 하나라도 참이 있으면 True, 모두 거짓이면 False
any([1, 2, 3, 0])
>>> True
any([0, ""])
>>> False

# chr : 아스키 코드 값을 입력받아 그 코드에 해당하는 문자 출력
chr(97)
>>> 'a'

# dir : 객체기 자체적으로 가지고 변수나 함수를 보여줌
dir([1, 2, 3])
>>> ['append', 'count', ...]

# divmod : 두 숫자를 나눈 몫과 나머지를 튜플 형태로 반환
divmod(7, 3)
>>> (2, 1)

# enumerate : 순서가 있는 자료형을 입력으로 받아 인덱스 값을 포함하는 enumerate 객체 반환
for i, name in enumerate(['body', 'foo', 'bar']):
    print(i, name)
    
>>> 0 body
    1 foo
    2 bar

# eval : 실행 가능한 문자열을 입력으로 받아 문자열을 실행한 결괏값 반환
eval('1+2')
>>> 3
eval("'hi' + 'a'")
>>> 'hia'

# filter : 첫 번째 인수로 함수 이름, 두 번째 인수로 그 함수에 차례로 들어갈 반복 가능한 자료형을 받는다.
#          그리고 두 번째 인수인 반복 가능한 자료형 요소가 첫 번째 인수인 함수에 입력되었을 때 반환 값이
#          참인 것만 묶어서(걸러서) 반환
def positive(x):
    return x > 0

print(list(filter(positive, [1, -3, 2, 0, -5, 6])))
>>> [1, 2, 6]

# hex : 정수 값을 입력받아 16진수로 변환
hex(234)
>>> '0xea'

# id : 객체를 입력받아 객체의 고유 주소 값 반환
a = 3
id(3)
>>> 135072304

# input : 사용자 입력을 받는 함수
a = input("Enter : ")
>>> Enter : hi
a
>>> 'hi'

# int : 문자열 형태의 숫자나 소수점이 있는 숫자 등을 정수 형태로 반환
int('3') # 문자열 형태 3
>>> 3
int(3.4)
>>> 3

# isinstance : 첫 번째 인수로 인스턴스, 두 번째 인수로 클래스 이름
#              입력으로 받은 인스턴스가 그 클래스의 인스턴스인지를 판단
#              참이면 True, 거짓이면 False
class Person: pass # 아무 기능이 없는 Person 클래스 생성
...
a = Person() # Person 클래스의 인스턴스 a 생성
isinstance(a, Person) # a가 Person 클래스의 인스턴스인지 확인
>>> True

# len : 입력값의 길이 반환
len("python")
>>> 6
len([1, 2, 3])
>>> 3

# list : 반복 가능한 자료형을 입력받아 리스트로 반환
list("python")
>>> ['p', 'y', 't', 'h', 'o', 'n']
list((1, 2, 3)) # 튜플 자료형
>>> [1, 2, 3]

# map : 함수와 반복 가능한 자료형을 입력으로 받음
#       입력 받은 자료형의 각 요소를 함수 f가 수행한 결과를 묶어서 돌려주는 함수
def two_times(x): return x*2
...
list(map(two_times, [1, 2, 3, 4]))
>>> [2, 4, 6, 8]

# max : 인수로 반복 가능한 자료형을 입력받아 그 최댓값 반환
max([1, 2, 3])
>>> 3
max("python")
>>> 'y'

# min : 인수로 반복 가능한 자료형을 입력받아 그 최솟값 반환
min([1, 2, 3])
>>> 1
min("python")
>>> 'h'

# oct : 정수 형태의 숫자를 8진수 문자열로 반환
oct(34)
>>> '0o42'

# open : '파일 이름'과 '읽기 방법'을 입력받아 파일 객체를 반환
#         읽기 방법을 생략하면 기본값인 읽기 전용 모드(r)
# w : 쓰기 모드, r : 읽기 모드, a : 추가 모드, b : 바이너리 모드(b는 w, r, a와 함께 사용)
f = open("binary_file", "rb") # b를 추가하면 바이너리 모드 추가(바이너리 읽기 모드)

# ord : 문자의 아스키 코드 값 반환
ord('a')
>>> 97

# pow : x의 y 제곱한 결괏값 반환
pow(2, 4)
>>> 16

# range : 입력받은 숫자에 해당하는 범위 값을 반복 가능한 객체로 만들어 반환
list(range(5))
>>> [0, 1, 2, 3, 4]
list(range(5, 10))
>>> [5, 6, 7, 8, 9]
list(range(1, 10, 2)) # 세 번째 인수는 숫자 사이의 거리
>>> [1, 3, 5, 7, 9]

# round : 숫자를 입력받아 반올림
round(4.6)
>>>5

# sorted : 입력값을 정렬한 후 결과를 리스트로 반환
sorted([3, 1, 2])
>>> [1, 2, 3]
sorted("zero")
>>> ['e', 'o', 'r', 'z']

# str : 문자열 형태로 객체를 변환
str(3)
>>> '3'
str('hi'.upper())
>>> 'HI'

# sum : 입력받은 리스트나 튜플의 모든 요소의 합을 반환
sum([1, 2, 3])
>>> 6

# tuple : 반복 가능한 자료형을 입력받아 튜플 형태로 바꾸어 반환
tuple("abc")
>>> ('a', 'b', 'c')
tuple([1, 2, 3])
>>> (1, 2, 3)
tuple((1, 2, 3))
>>> (1, 2, 3)

# type : 입력값의 자료형이 무엇인지 알려줌
type("abc")
>>> <class 'str'> # "abc"는 문자열 자료형

# zip : 동일한 개수로 이루어진 자료형을 묶어 주는 역할
list(zip([1, 2, 3], [4, 5, 6]))
>>> [(1, 4), (2, 5), (3, 6)]
list(zip("abc", "de"))
>>> [('a', 'd'), ('b', 'e')]

 

05-2 ~ 05-3 (p.207 ~ p.221)

 

점점 진도가 나갈수록 심화되는 내용이 나오다 보니 확실히 전보다 더 공부하는 시간이 오래 걸린다.

공부 시간이 오래 걸리는 데는 교재에 나와 있지 않은 예들을 실행되는지 테스트해 보느라고 그런 것도 있는 것 같다.

하지만 공부한 것들을 이해하게 되면 지나간 시간이 아깝지 않다. 프로그래밍 공부는 될 때까지 시도해 보는 근성도 중요한 것 같다.

 

아무도 나를 막을 수 없으셈!

 


 

05-2 모듈

 

모듈이란 함수나 변수 또는 클래스를 모아 놓은 파일이다.

다른 파이썬 프로그램에서 불러와 사용할 수 있게끔 만든 파이썬 파일이다.

다른 사람이 이미 만들어 놓은 모듈을 사용할 수도 있고 직접 만들어서 사용할 수도 있다.

# 모듈의 예
# mod1.py
def add(a, b):
    return a + b
    
def suv(a, b):
    return a - b
# .py로 만든 파이썬 파일은 모두 모듈

 

모듈 불러오기

# 명령프롬프트(cmd)
C:\Users\a_jb97> cd C:\doit # mod1.py를 저장한 디렉터리로 이동
C:\doit>dir # C:\doit 디렉터리에 파일이 있는지 확인
...
2022-02-10 오후 09:10 50 mod1.py
...
C:\doit> python # 대화형 인터프리터 실행
>>> import mod1 # import는 이미 만들어 놓은 파이썬 모듈을 사용할 수 있게 해주는 명령어
                # import는 현재 디렉터리에 있는 파일이나 파이썬 라이브러리가 저장된 디렉터리에 있는 모듈만 불러올 수 있음
                # 모듈 이름은 .py를 제거한 mod1만 작성
>>> print(mod1.add(3, 4)) # add 함수를 사용하기 위해서는 모듈 이름 뒤에 '.'(도트 연산자)를 붙이고 함수 이름
7
>>> print(mod1.sub(4, 2))
2

# 모듈 이름 없이 함수 이름만 쓰고 싶을 때
>>> from mod1 import add
>>> add(3, 4)
7

# add, sub 함수 둘 다 사용하고 싶을 때
1. from mod1 import add, sub
2. from mod1 import* # *는 '모든 것'이라는 뜻

 

if __name__ = "__main__": 의 의미

# mod1.py
def add(a, b):
    return a + b
    
def suv(a, b):
    return a - b
    
print(add(1, 4))
print(sub(4, 2))

# cmd
C:\doit> python
>>> import mod1
5
2 # mod1.py 파일의 add와 sub 함수만 사용하려고 했는데 결괏값이 출력


# 이러한 문제 방지
# mod1.py
def add(a, b):
    return a + b
    
def suv(a, b):
    return a - b

if __name__ == "__main__": # 직접 파일을 실행하면 참이 되어 if문 다음 문장 수행
                           # 대화형 인터프리터나 다른 파일에서 이 모듈을 불러서 사용할 때는 거짓이 되어 if문 다음 문장이 수행되지 않음
    print(add(1, 4))
    print(sub(4, 2))
   
import mod1
>>> # 아무것도 수행되지 않음

 

클래스나 변수 등을 포함한 모듈

# mod2.py
PI = 3.141592

class Math:
    def solv(self, r):
        return PI * (r ** 2)
    
def add(a, b):
    return a + b

# cmd
C:\doit>python
>>> import mod2
>>> print(mod2.PI) # mod2.py에 있는 PI 변수 값 사용

>>> a = mod2.Math()
>>> print(a.solv(2)) # mod2.py에 있는 Math 클래스 사용
12.566368

>>> print(mod2.add(mod2.PI, 4.4)) # mod2.py에 있는 add 함수 사용
7.541592

 

다른 파일에서 모듈 불러오기

# modtest.py
import mod2 # mod2.py 파일을 불러옴
            # 현재 모듈과 불러올 모듈이 동일한 디렉터리에 있어야 함
result = p212.add(3, 4)
print(result)

* 모듈을 불러오는 또 다른 방법(모듈을 저장한 디렉터리로 이동하지 않고 모듈을 불러와서 사용)

# cmd
C:\doit>mkdir mymod # 새 디렉터리 생성
C:\doit>move mod2.py mymod # 지정한 디렉터리로 파일 이동
        1개 파일을 이동했습니다.

# 1. sys.path.append(모듈을 저장한 디렉터리) 사용하기
# cmd
C:\doit>python
>>> import sys # sys 모듈 불러옴
>>> sys.path # 파이썬 라이브러리가 설치되어 있는 디렉터리를 보여줌
>>> sys.path.append("C:\doit\mymod")
>>> sys.path
sys.path(파이썬 라이브러리)에 'C:\doit\mymod' 디렉터리 추가
>>> import mod2
>>> print(mod2.add(3, 4))
7

# 2. PYTHONPATH 환경 변수 사용하기
# cmd
C:\doit>set PYTHONPATH=C:\doit\mymod # set 명령어 사용해 PYTHONPATH 환경변수에 mod2.py 파일이 있는 C:\doit\mymod 디렉터리 설정
C:\doit>python
>>> import mod2
>>> print(mod2.add(3, 4))
7

 

05-3 패키지

 

패키지는 도트'.'를 사용하여 파이썬 모듈을 계층적(디렉터리 구조)으로 관리할 수 있게 해준다.

모듈 이름이 A.B인 경우, A는 패키지 이름이 되고 B는 A 패키지의 B 모듈이 된다.

패키지는 디렉터리, 파이썬 모듈로 이루어져 있다.

# 패키지의 구조 (ex.게임)
game/ # 디렉터리
  __init__.py # 모듈
  sound/
    __init__.py
    echo.py
    wav.py
  graphic/
    __init__.py
    screen.py
    render.py
  play/
    __init__.py
    run.py
    test.py

* 패키지 구조로 프로그램을 만들면 공동 작업이나 유지 보수가 용이하다.

 

패키지 만들기

패키지 기본 구성 요소 준비하기

  1. 디렉터리 생성(game, graphic, sound)

디렉터리 생성

  2. 각 디렉터리에 __init__.py 파일 생성

 

  3. 각 디렉터리에 필요한 모듈(.py파일) 생성

 

  4. game 패키지를 참조하도록 명령 프롬프트 창에서 set 명령어로 PYTHONPATH 환경 변수에 C:\doit 디렉터리 추가

 

패키지 안의 함수 실행하기

다음 예제들은 import 예제이므로 하나의 예제를 실행하고 나서 다음 예제를 실행할 때는 인터프리터를 종료하고 다시 실행. (윈도우는 인터프리터 종료 : Ctrl + z)

# cmd
# 1. echo 모듈을 import하여 실행
C:\doit>python
>>> import game.sound.echo
>>> game.sound.echo.echo_test()
echo

# 2. echo 모듈이 있는 디렉터리까지를 from...import 하여 실행
>>> from game.sound import echo
>>> echo.echo_test()
echo

# 3. echo 모듈의 echo_test함수를 직접 import하여 실행
>>> from game.sound.echo import echo_test
>>> echo_test()
echo

# 실행 불가능 예
>>> import game
>>> game.sound.echo.echo_test()
오류 발생 # import game을 수행하면 game 디렉터리의 모듈 또는 game 디렉터리의 __init__.py에 정의한 것만 참조 가능

>>> import game.sound.echo.echo_test
오류 발생 # 도트 연산자'.'를 사용해서 import a.b.c처럼 import할 때 가장 마지막 항목인 c는 반드시 모듈 또는 패키지여야만 함

 

__init__.py 의 용도

__init__.py 파일은 해당 디렉터리가 패키지의 일부임을 알려주는 역할을 한다.

만약 패키지에 포함된 디렉터리에 __init__.py 파일이 없다면 패키지로 인식되지 않는다.

* Python 3.3 버전부터는 __init__.py 파일이 없어도 패키지로 인식하지만 하위 버전 호환을 위해 생성하는 것이 좋다.

# cmd
C:\doit>python
>>> from game.sound import*
>>> echo.echo_test()
오류 발생

# 특정 디렉터리의 모듈을 *를 사용하여 import할때는 다음과 같이 해당 디렉터리의 __init__.py 파일에
  __all__ 변수를 설정하고 import할 수 있는 모듈을 정의해 주어야 한다.

# C:/doit/game/sound/__init__.py
__all__ = ['echo', 'ringtone']

# cmd
C:\doit>python
>>> from game.sound import*
>>> echo.echo_test()
echo

 

relative 패키지

# render.py
from game.sound.echo import echo_test # 추가하여 echo_test 함수를 사용할 수 있게 함
def render_test():
    print("render")
    echo_test()
    
# cmd
C:\doit>python
>>> from game.graphic.render import render_test
>>> render_test()
render
echo


# relative하게 import
# render.py
from ..sound.echo import echo_test # ..은 부모 디렉터리를 뜻함
                                   # graphic과 sound 디렉터리는 동일한 깊이이므로 사용 가능

def render_test():
    print("render")
    echo_test()
# ..같은 relative한 접근자는 모듈 안에서만 사용 가능

 

04장 연습문제 ~ 05~1 (p.179 ~ p.206)

 

오늘 공부한 클래스는 처음 접하는 개념이라서 이해를 하는데 전보다는 시간이 더 걸렸다.

클래스를 공부하기 전에 4장 연습문제를 풀었는데 한 문제씩 정답을 맞히니 기분이 좋았다.

이 기분을 양분으로 삼아서 더 열심히 해야겠다.

 

기분이 조크든요

 


 

5장 : 파이썬 날개 달기

 

5장에서는 프로그래밍의 꽃이라 할 수 있는 클래스와 모듈, 예외 처리 및 파이썬 라이브러리에 대해서 배운다. 여기까지 끝내면 파이썬 프로그램을 작성하기 위해 알아야 할 대부분의 내용을 배우게 된다고 한다.

 

05-1 클래스

 

클래스는 프로그램 작성을 위해 꼭 필요한 건 아니지만, 적재적소에 사용하면 매우 편리한 요소이다.

# 클래스의 예
class Calculator:
    def __init__(self):
        self.result = 0
    
    def add(self, num):
        self.result += num
        return self.result

cal1 = Calculator()
cal2 = Calculator()

* 클래스(class)란 똑같은 무언가를 계속해서 만들어 낼 수 있는 설계 도면(과자 틀)이고, 객체(object)란 클래스로 만든 피조물(과자)을 뜻한다.

클래스는 함수처럼 구조는 여러 로직들을 모아놓은 모양새지만 가장 큰 특징은 같은 클래스로 생성한 여러 가지 다른 이름의 객체(cal1, cal2)들은 서로 영향을 받지 않고 독립적인 값을 유지한다는 것이다.

 

* 클래스로 만든 객체를 인스턴스라고도 한다. 객체와의 차이는 'cal1 = Calculator()'에서 cal1은 객체이고 a객체는 Calculator의 인스턴스이다.

 

사칙연산 클래스 만들기

클래스는 무작정 만드는 것보다 클래스로 만든 객체를 중심으로 어떤 식으로 동작하게 할 것인지 미리 구상을 한 후에 생각한 것들을 하나씩 해결하면서 완성해 나가는 것이 좋다.(메서드 = 클래스 안에 구현된 함수)

사칙연산 클래스(FourCal)
setdata 메서드 두 숫자 입력
add 메서드 더하기 기능
mul 메서드 곱하기 기능
sub 메서드 빼기 기능
div 메서드 나누기 기능

 

# 사칙연산 클래스
class FourCal: # 클래스 구조
    def setdata(self, first, second): # 객체에 숫자 지정 
                                      # a 객체를 만들면(a.setdata(4, 2)) 첫 번째 매개변수 self에는 setdata메서드를 호출한 객체 a가 자동으로 전달
        self.first = first
        self.second = second
    def add(self): # 매개변수 = self, 반환값 = result
        result = self.first + self.second # = result = a.first + a.second
        return result
    def mul(self):
        result = self.first * self.second
        return result
    def sub(self):
        result = self.first - self.second
        return result
    def div(self):
        result = self.first / self.second
        return result
        
a = FourCal()
b = FourCal()
a.setdata(4, 2)
b.setdata(3, 8)

a.add()
>>> 6
a.mul()
>>> 8
a.sub()
>>> 2
a.div()
>>> 2

b.add()
>>> 11
b.mul()
>>> 24
b.sub()
>>> -5
b.div()
>>> 0.375

 

생성자(Constructor)

객체에 초깃값을 설정해야 할 필요가 있을 때는 setdata와 같은 메서드를 호출하여 초깃값을 설정하기보다는 생성자를 구현하는 것이 안전한 방법이다.

 

* 생성자(Constructor)란 객체가 생성될 때 자동으로 호출되는 메서드를 의미한다. 파이썬 메서드 이름으로 __init__를 사용하면 생성자 생성

# FourCal 클래스에 생성자 사용
class FourCal:
    def __init__(self, first, second): # 생성자로 인식
        self.first = first
        self.second = second
    def setdata(self, first, second):
        self.first = first
        self.second = second
    def add(self):
        result = self.first + self.second
        return result
    def mul(self):
        result = self.first * self.second
        return result
    def sub(self):
        result = self.first - self.second
        return result
    def div(self):
        result = self.first / self.second
        return result
        
a = FourCal(4, 2) # 생성자로 인해 a.first = 4, a.second = 2 바로 대입
print(a.first)
>>> 4
print(a.second)
>>> 2

a.add()
>>> 6
a.div()
>>> 2.0

 

클래스의 상속

'재산을 상속받다'의 상속과 같은 의미로 어떤 클래스를 만들 때 다른 클래스의 기능을 물려받을 수 있게 한다.

class FourCal:
    def __init__(self, first, second):
        self.first = first
        self.second = second
    def setdata(self, first, second):
        self.first = first
        self.second = second
    def add(self):
        result = self.first + self.second
        return result
    def mul(self):
        result = self.first * self.second
        return result
    def sub(self):
        result = self.first - self.second
        return result
    def div(self):
        result = self.first / self.second
        return result

# 클래스의 상속
class MoreFourCal(FourCal): # class 클래스 이름(상속할 클래스 이름):
    def pow(self):
        result = self.first ** self.second # 제곱
        return result
# FourCal 클래스를 상속했으므로 FourCal 클래스의 모든 기능 사용 가능

a = MoreFourCal(4, 2)
a.add()
>>> 6
a.mul()
>>> 8
a.sub()
>>> 2
a.div()
>>> 2
a.pow() # 제곱
>>> 16

# 메서드 오버라이딩(상속한 클래스에 있는 메서드를 동일한 이름으로 다시 만드는 것)
a = FourCal(4, 0)
a.div()
>>> ZeroDivisionError 오류 # 4를 0으로 나누려고 하기 때문에 오류 발생

class SafeFourCal(FourCal):
    def div(self):
        if self.second == 0:
            return 0 # div 메서드에서 0으로 나누면 0 반환
        else:
            return self.first / self.second
            
a = SafeFourCal(4, 0)
a.div()
>>> 0

 

클래스 변수

# 클래스 변수
class Family:
    lastname = "김"

print(Family.lastname)
>>> 김

a = Family()
b = Family()
print(a.lastname)
>>> 김
print(b.lastname)
>>> 김

Family.lastname = "박"
print(a.lastname)
>>> 박
print(b.lastname)
>>> 박
# 클래스 변수는 클래스로 만든 모든 객체에 공유됨

 

04-2 ~ 04-3 (p.168 ~ p.178)

 

이제 반 정도 왔다. 여기까지 오니까 슬슬 초반에 배웠던 부분들이 가물가물해지려고 한다. 매일마다 복습도 꾸준히 해야겠다.

아직까지는 지금까지 배운 걸로 프로그램을  만들 수 있을 것 같은 느낌은 들지 않는다. 그래서 아직 불안한 느낌이 드는지도 모르겠다. 계속해서 공부를 하는 수밖에 없을 거 같다.

 

열심 또 열심히..!

 


 

04-2 사용자 입력과 출력

 

사용자의 입력을 받는 방법과 출력하는 방법은 여러 가지가 있다.

 

사용자 입력

사용자가 입력한 값을 어떤 변수에 대입하려고 할 때는 이런 방법들이 있다.

# input의 사용
a = input()
>>> Life is too short, you need python
a
>>> 'Life is too short, you need python'
# input은 입력되는 모든 것을 문자열로 취급한다.


# 프롬프트 값을 띄워서 사용자 입력받기
# input("내용 입력")
number = input("숫자를 입력하세요 : ")
>>> 숫자를 입력하세요 : 3
print(number)
>>> 3

 

print 자세히 알기

print문으로 할 수 있는 일은 여러 가지가 있다.

# 큰따옴표(")로 둘러싸인 문자열은 + 연산과 동일하다
print("life" "is" "too short")
>>> lifeistoo short
print("life" + "is" + "too short")
>>> lifeistoo short

# 문자열 띄어쓰기는 콤마로 한다
print("life", "is", "too short")
>>> life is too short

# 한 줄에 결괏값 출력하기
for i in range(10):
    print(i, end=' ') # end 사용

>>> 0 1 2 3 4 5 6 7 8 9 >>>

 

04-3 파일 읽고 쓰기

 

이제까지는 값을 '입력'받을 때는 사용자가 직접 입력하는 방식을 사용했고 '출력'할 때는 모니터 화면에 결괏값을 출력하는 방식으로 프로그래밍해 왔다. 하지만 입출력 방법에는 꼭 이것만 있는 것은 아니다. 여기에서는 파일을 통한 입출력 방법을 배웠다.

 

파일 생성하기

f = open("새파일.txt", 'w')
f.close()

# 파일 객체 = open(파일 이름, 파일 열기 모드)
# open 함수는 '파일 이름'과 ' 파일 열기 모드'를 입력값으로 받고 결괏값으로 파일 객체를 돌려준다.

# C:/doit 디렉터리에 생성하고 싶을 때
f = open("C:/doit/새파일.txt", 'w')
f.close()
파일 열기 모드 설명
r 읽기 모드 - 파일을 읽기만 할 때 사용
w 쓰기 모드 - 파일에 내용을 쓸 때 사용
a 추가 모드 - 파일의 마지막에 새로운 내용을 추가할 때 사용

* 파일을 쓰기 모드로 열면 해당 파일이 이미 존재할 경우 원래 있던 내용이 모두 사라지고, 해당 파일이 존재하지 않으면 새로운 파일이 생성된다.

* 프로그램을 종료할 때 파이썬 프로그램이 열려 있는 파일의 객체를 자동으로 닫아 주기 때문에 close()는 생략해도 되지만 되도록이면 사용해 주는 것이 좋다. 쓰기 모드로 열었던 파일을 닫지 않고 다시 사용하려고 하면 오류가 발생하기 때문이다.

 

파일을 쓰기 모드로 열어 출력 값 적기

이번에는 프로그램의 출력 값을 파일에 직접 써본다.

f = open("C:/doit/새파일.txt", 'w')
for i in range(1, 11):
    data = "%d번째 줄입니다.\n" % i
    f.write(data)
f.close()

# 실행하면 1번째 줄입니다. ~ 10번째 줄입니다. 라고 적혀있는 메모장 파일이 생성된다.

 

프로그램의 외부에 저장된 파일을 읽는 여러 가지 방법

파이썬에는 외부 파일을 읽어 들여 프로그램에서 사용할 수 있는 여러 가지 방법이 있다.

# readline 함수 사용하기
f = open("C:/doit/새파일.txt", 'r')
line = f.readline()
print(line)
f.close()
# readline 함수는 파일의 첫 번째 줄을 읽어 출력하는 함수이다.
# 실행하면 새파일.txt의 가장 첫 번째 줄인 '1번째 줄입니다.'가 출력된다.

# readlines 함수 사용하기
f = open("C:/doit/새파일.txt", 'r')
lines = f.readlines()
for line in lines:
    print(line)
f.close()
# readlines 함수는 파일의 모든 줄을 읽어서 각각의 줄을 요소로 갖는 리스트로 돌려준다.

# read 함수 사용하기
f = open("C:/doit/새파일.txt", 'r')
data = f.read()
print(data)
f.close()
# f.read()는 파일의 내용 전체를 문자열로 돌려준다.

 

파일에 새로운 내용 추가하기

원래 있던 값을 유지하면서 새로운 값을 추가해야 할 경우에는 파일을 추가 모드('a')로 열면 된다.

# 추가 모드를 사용한 예
f = open("C:/doit/새파일.txt", 'a')
for i in range(11, 20):
    data = "%d 번째 줄입니다.\n" % i
    f.write(data)
f.close()
# 실행하면 '10번째 줄입니다.'의 뒤를 이어 '11번째 줄입니다' ~ '19번째 줄입니다'까지 출력된다.

 

with문과 함께 사용하기

지금까지는 항상 코드 마지막에 f.close()를 추가해서 파일을 닫아왔다. 파일을 열면 항상 close 해 주는 것이 좋다.

하지만 with문을 사용하면 파일을 열고 닫는 것을 자동으로 처리할 수 있다.

# with문을 사용한 예
with open("foo.txt", "w") as f:
    f.write("Life is too short, you need python")
# with문을 사용하면 with 블록을 벗어나는 순간 열린 파일 객체 f가 자동으로 close 된다.

 

03장 연습문제 ~ 04-1 (p.146 ~ p.167)

 

이번 주는 설 연휴가 있어서 토요일이 되어서야 6일 차 공부를 할 수 있었다.

며칠을 쉬다가 다시 공부를 하려니까 초큼 힘들었다...😂

6일 차인데 벌써 함수 부분까지 왔다. 책의 권장 진도보다 2배가 빠른 만큼 전에 배운 내용을 잊지 않기 위해 복습도 철저하게 해야겠다.

 

가지마아아...

 


 

03장 연습문제는 확실히 2장에서 배운 내용까지 합쳐서 나오다 보니 2장 연습문제보다는 조금 난이도가 있었다.

헷갈리는 부분은 전에 작성한 블로그 글을 훑어보니 해결할 수 있었다.

 

4장 : 프로그램의 입력과 출력

 

4장에서는 프로그램의 입력과 출력을 다루는 방법을 설명하는데 그중에서 오늘은 함수에 대해서 배웠다.

입출력 부분은 프로그래밍의 설계과 밀접한 관련이 있기 때문에 매우 중요한 부분이기도 하다.

 

04-1 함수

 

함수는 과일이 입력, 과일 주스가 출력이라면 믹서는 함수에 비유할 수 있다.

즉, 입력값을 가지고 어떤 일을 수행한 다음에 그 결과물을 내놓는 일을 하는 것이 함수이다.

 

함수를 사용하는 이유

함수는 프로그래밍을 하다 보면 똑같은 내용을 반복해서 작성하는 경우가 있을 때 사용하면 시간도 절약할 수 있고 코드도 일목요연하게 작성할 수 있어서 가독성 측면에서 장점이 있다. 그래서 버그를 확인할 때도 유용할 수 있다.

# 파이썬 함수의 기본적인 구조
def 함수이름(매개변수):
    수행할 문장1
    수행할 문장2
    ...
    
# 기본적인 예
def add(a, b): # a, b는 매개변수
    return a + b # return은 함수의 결괏값을 돌려주는 명령어 
                 # 이 함수의 이름은 add이고 입력으로 2개의 값을 받으며 결괏값은 2개의 입력값을 더한 값이다.

print(add(3, 4)) # 3, 4는 인수
>>> 7

 

입력값과 결괏값에 따른 함수의 형태

함수의 형태는 입력값과 결괏값의 존재 유무에 따라 4가지 유형으로 나뉜다.

# 일반적인 함수
def add(a, b):
    result = a + b
    return result
    
a = add(3, 4) # 결괏값을 받을 변수 = 함수이름(입력인수1, 입력인수2, ...)
print(a)
>>> 7


# 입력값이 없는 함수
def say():
    return 'Hi'

a = say() # 결괏값을 받을 변수 = 함수이름()
print(a)
>>> Hi


# 결괏값이 없는 함수
def add(a, b):
    print("%d, %d의 합은 %d입니다." % (a, b, a+b))
    
add(3, 4) # 함수이름(입력인수1, 입력인수2, ...)
>>> 3, 4의 합은 7입니다.


# 입력값도 결괏값도 없는 함수
def say():
    print('Hi')
    
say() # 함수이름()
>>> Hi

 

매개변수 지정하여 호출하기

def add(a, b):
    return a+b
    
result = add(a=3, b=7) # a에 3, b에 7을 전달
print(result)
>>> 10

result = add(b=7 a=3) # 순서 상관 없이 사용 가능
print(result)
>>> 10

 

입력값이 몇 개가 될지 모를 때

매개변수 앞에 *를 붙인다.

def add_mul(choice, *args): # 매개변수 args 앞에 *, 다른 매개변수 추가 사용 가능
    if choice == "add":
        result = 0
        for i in args:
            result = result + i
    elif choice == "mul":
        result = 1
        for i in args:
            result = result * i
    return result
    
result = add_mul('add', 1,2,3,4,5)
print(result)
>>> 15
result = add_mul('mul', 1,2,3,4,5)
print(result)
>>> 120

 

키워드 파라미터

def print_kwargs(**kwargs): # 매개변수 앞에 **를 붙이면 입력값이 딕셔너리로 출력
    print(kwargs)
    
print_kwargs(a=1)
>>> {'a' : 1}
print_kwargs(name='foo', age=3)
>>> {'age' : 3, 'name' : 'foo'}

 

* 함수의 결괏값은 언제나 하나이다.

def add_and_mul(a,b):
    return a+b, a*b
    
result = add_and_mul(3,4)
print(result)
>>> (7, 12) # 결괏값을 튜플로 돌려준다.

def add_and_mul(a,b):
    return a+b
    return a*b
    
result = add_and_mul(3,4)
print(result)
>>> 7 # 결괏값은 언제나 하나이기 때문에 첫 번째 return문만 반환

 

* return은 단독으로 사용해서 함수를 빠져나올 때 사용할 수도 있다.

 

매개변수 초깃값 미리 설정하기

def say_myself(name, old, man=True): # 매개변수에 들어갈 값이 항상 변하는 것이 아닐 경우에 유용
    print("나의 이름은 %s입니다." % name)
    print("나이는 %d살입니다." % old)
    if man:
        print("남자입니다.")
    else:
        print("여자입니다.")
        
say_myself("홍길동", 26)
>>> 나의 이름은 홍길동입니다.
    나이는 26살입니다.
    남자입니다.
say_myself("홍길동", 26, True)
>>> 나의 이름은 홍길동입니다.
    나이는 26살입니다.
    남자입니다.
say_myself("홍길순", 26, False)
>>> 나의 이름은 홍길동입니다.
    나이는 26살입니다.
    여자입니다.

# 초기화시키고 싶은 매개변수는 항상 맨 뒤쪽에 놓아야 한다.

 

함수 안에서 선언한 변수의 효력 범위

함수 안에서 사용하는 매개변수는 함수 밖의 변수 이름과는 전혀 상관이 없기 때문에 서로 같은 변수로 취급하면 안 된다.

a = 1
def vartest(a):
    a = a + 1
    
vartest(a)
print(a)
>>> 1 # 함수 밖의 a 변수와 함수 안의 a변수는 서로 다른 것이기 때문에 결괏값이 2가 아닌 1


def vartest(a):
    a = a + 1
    
vartest(3)
print(a)
>>> 오류 발생 # print(a)에서 입력받아야 하는 a 변수가 존재하지 않기 때문(함수 밖에 변수가 존재하지 않는다.)
# 함수 안에서 함수 밖의 변수를 변경하는 방법

# 1. return 사용하기
b = 1
def vartest(a):
    a = a + 1
    return a
    
b = vartest(b) # b가 vartest 함수의 결괏값으로 바뀜. b 변수가 vartest 함수의 a 매개변수에 대입됨
print(b)
>>> 2


# 2. global 명령어 사용하기
a = 1
def vartest():
    global a # 함수 안에서 함수 밖의 a 변수를 직접 사용하겠다는 뜻
    a = a + 1
    
vartest()
print(a)
>>> 2 # global 명령어는 되도록 사용하지 않는 것이 좋음
      # 함수는 독립적으로 존재하는 것이 좋기 때문
      # 외부 변수에 종속적인 함수는 그다지 좋은 함수가 아님

 

lambda

함수를 생성할 때 사용하는 예약어로 def와 동일한 역할. 보통 함수를 한 줄로 간결하게 만들 때 사용한다.

# lambda의 구조
lambda 매개변수1, 매개변수2, ...: 매개변수를 사용한 표현식

# lambda의 예
add = lambda a, b: a+b
result = add(3, 4)
print(result)
>>> 7

# 이 함수와 동일
def add(a, b):
    return a+b

result = add(3, 4)
print(result)
>>> 7

 

+ Recent posts