[Python] 6장 프로그래밍

미남잉·2021년 10월 27일
0

파이썬을 몇 번 배웠던 적이 있는데 for문 10분 가르쳐주고 자, 구구단 만들어보세요.하는 사람들 정말 많았습니다. 구구단에 좌절하지 맙시다. 점프투파이썬에서도 꽤 뒤에 나오고, 책에도 적혀 있지만 파이썬 기본 문법은 배웠지만 구구단은 못 만들었다라고 저자가 설명합니다.

전 참고로 크리스마스 트리에서 좌절했습니다...🎄 그것 때문에 '난 코딩에 재능이 없어ㅠㅠ'라고 느끼는 것만큼 슬픈 일도 없는 것 같습니다. 지나와서 생각해보면... 이 책 두 번 보고 구구단 만드는 저도 있는데... 코딩 열심히 해봅시다. 파이팅🤩



1. 구구단 만들기

구구단 만들기에 한이라도 들렀나. 구구단에 미친놈 아닙니다. ㅋㅋㅋ

# 입력하는 값의 단 만들기
result = []
n = int(input('몇 단을 만들고 싶으십니까?'))
for i in range(1,10):
    num = n * i
    result.append(num)
print(result)
# 2~9단까지 만들기
for i in range(2, 10):
    for n in range(1, 10):
        print(i, '*', n, '=', i*n)
# 2~9단 더 예쁘게 만들기
for i in range(2, 10):
    print('-----', i, '단입니다-----')
    for n in range(1, 10):
        print(i, '*', n, '=', i*n)
# 2~9단 리스트에 모두 담기
result = []
for i in range(2, 10):
    for n in range(1, 10):
        num = n * i
        result.append(num)
print(result)
# while문으로 해보기
i = 1
while i < 9:
    i += 1
    j = 1
    print('-----', i, '단입니다-----')
    while j < 10:
        print(i, '*', j, '=', i*j)
        j += 1
# 입력받은 수까지만 구구단 출력하기 +) break
x = int(input('몇 단까지 원하시나요?==>'))
i = 1
while i < 9:
    i += 1
    j = 1
    print('---', i, '단입니다---')
    while j < 10:
        print(i, '*', j, '=', i*j)
        j += 1
    if i == x:
        break

참고로 교재에 나오는 코드는 GuGU 함수 만들기입니다.

def GuGu(n):
	result = []
    	i = 1
        while i < 10:
        	result.append(n*i)
            i = i + 1
       	return result
        
print(GuGu(2))

함수를 풀어준다면

n = int(input('만들고 싶은 구구단 입력하삼=->'))
result = []
i = 1
while i < 10:
    result.append(n*i)
    i += 1

print(result)

아 불태웠다.😵🔥



2. 3과 5의 배수 합하기

이 문제는 저번에도 제대로 이해를 못했는데, 이번에도 헷갈렸습니다.

  • 3과 5의 배수를 구해 합하는 문제
  • 3과 5의 공배수를 구해 합하는 문제가 아님
  • 각각 3, 5의 배수를 각각 구해 모두 더해주란 뜻
  • 이 문제의 목적은 3과 5의 공배수를 중복으로 더해선 안 된다는 것
  • 그걸 위해 or 연산자를 사용해야 함
result = 0

for i in range(1, 1000):
	if i % 3 == 0 or i % 5 == 0:
    	result += i
        
print(result)


3. 게시판 페이징하기

※ 이렇게 게시판의 페이지 수를 보여 주는 것을 "페이징"한다고 부른다.

  • 함수 이름은? getTotalPage
  • 입력 받는 값은? 게시물의 총 건수(m), 한 페이지에 보여줄 게시물 수(n)
  • 출력하는 값은? 총 페이지수
게시물의 총 건수(m)페이지당 보여줄 게시물 수(n)총 페이지 수
5101
15102
25103
30103
# 첫 번째 코드

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))   # 4 출력

※ 주의점❗ 네 번째 케이스는 총 건수가 30이고 한 페이지에 보여 줄 건수가 10인데 4가 출력되어 실패해 버렸다.

def getTotalPage(m, n):
    if m % n ==0:
	    return m // n
    else:
            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. 간단한 메모장 만들기

원하는 메모를 파일에 저장하고 추가 및 조회가 가능한 간단한 메모장을 만들어 봅시다.

필요한 기능은?

  • 메모 추가하기
  • 메모 조회하기

입력 받는 값은?

  • 메모 내용
  • 프로그램 실행 옵션

출력하는 값은?

  • memo.txt

가장 먼저 해야 할 일은 메모를 추가하는 것입니다. 다음 명령을 실행했을 때 메모를 추가할 수 있도록 만들어 봅시다!

python memo.py -a "Life is too short"

memo.py는 작성할 파이썬 프로그램 이름입니다. –a는 이 프로그램의 실행 옵션이고, "Life is too short"는 추가할 메모 내용이 됩니다.

  1. 메모를 출력하는 코드를 작성해봅시다.
# memo.py
import sys

option = sys.argv[1]
memo = sys.argv[2]

print(option)
print(memo)

sys.argv는 프로그램을 실행할 때 입력된 값을 읽어 들일 수 있는 파이썬 라이브러리입니다.

sys.argv[0]은 입력받은 값 중 파이썬 프로그램 이름인 memo.py입니다. 그러므로 우리가 필요한 건 sys.argv[1]과 sys.argv[2]입니다.

sys.argv[1] -> 프로그램 실행 옵션 값
sys.argv[2] -> 메모 내용

  1. memo.py를 작성했다면 다음 명령 수행
C:\doit\python memo.py -a 'Life is too short'
-a
Life is too short

입력으로 전달한 옵션과 메모 내용이 그대로 출력됩니다.

  1. 입력으로 받은 메모를 파일에 쓰도록 코드를 변경합니다.
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()

옵션이 -a인 경우에만 memo 값을 읽어 memo.txt 파일에 그 값을 쓸 수 있도록 코드를 작성했습니다.

메모는 항상 새로운 내용이 쓰이는 것이 아닌 한 줄씩 추가되는 방식으로 파일 모드를 'a'로 설정했고 줄바꿈이 되도록 '\n'을 추가했습니다.

  1. 다음과 같은 명령을 수행해 보겠습니다.
C:\doit>python memo.py -a "Life is too short"  
C:\doit>python memo.py -a "You need python"

그러면 memo.txt 파일에는

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

추가한 메모가 잘 쓰여졌습니다.

  1. 작성한 메모를 출력하는 부분

메모 추가는 –a 옵션을 사용하고 메모 출력은 –v 옵션을 사용합니다.

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':
    f = open('memo.txt')
    memo = f.read()
    f.close()
    print(memo)

옵션으로 –v가 들어온 경우 memo.txt 파일을 읽어서 출력합니다.

  1. 코드를 수정한 후 다음과 같은 명령을 수행해 보자.
C:\doit>python memo.py -v
Life is too short
You need python

해당 문제는 sys를 활용할 수 있는지, 파일을 열고 닫기, 열기 모드 등을 이해하고 있는지를 확인하는 문제 같습니다.

※ 파일을 생성하는 기본 방법

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

※ 열기 모드 참고

파일 열기 모드설명
r읽기 모드 - 파일을 읽기만 할 때 사용
w쓰기 모드 - 파일에 내용을 쓸 때 사용
a추가 모드 - 파일의 마지막에 새로운 내용을 추가 시킬 때 사용


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

이번에는 문서 파일을 읽어서 그 문서 파일 안에 있는 탭(tab)을 공백(space) 4개로 바꾸어 주는 스크립트를 작성해 볼겁니다.

먼저 뭐가 떠오르시나요? 저는 replace('\t', ' ')의 사용이 먼저 떠올랐습니다. 저자는 입출력을 생각하라고 강조했습니다. 해야할 것을 정리해보면

  • 필요한 기능? 파일 읽기, 문자열 변경
  • 입력 받는 값? 탭을 포함한 문서 파일
  • 출력하는 값? 탭이 공백 4개로 수정된 문서 파일

python tabto4.py src dst 다음과 같은 형식으로 프로그램이 수행되도록 만들 예정입니다.

  • tabto4.py: 우리가 작성해야 할 파이썬 프로그램 이름
  • src: 탭을 포함하고 있는 원본 파일 이름
  • dst: 파일 안의 탭을 공백 4개로 변환한 결과를 저장할 파일 이름

예를 들어, a.txt 파일에 있는 탭을 4개의 공백으로 바꾸어서 b.txt에 저장하고 싶다면 다음과 같이 수행해야 합니다.

python tabto4.py a.txt b.txt

  1. tabto4.py 파일을 작성
import sys

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

print(src)
print(dst)

sys.argv를 사용하여 입력값을 확인하도록 만든 코드

  1. 입력이 정상적으로 출력되는지 확인
C:\doit>python tabto4.py a.txt b.txt
a.txt
b.txt
  1. 테스트를 위한 원본 파일(탭을 포함하는 파일)인 a.txt를 아래와 같이 작성. 각 단어는 \t 문자로 분리되도록 입력
Life	is	too	short
You	need	python
  1. 이제 탭 문자를 포함한 a.txt 파일을 읽어 탭을 공백 4개로 변환할 수 있도록 코드 작성
import sys

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

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

space_count = tab_content.replace('\t', ' '*4)
print(space_content)

위 코드는 src에 해당되는 입력 파일을 읽어서 그 내용을 tab_content라는 변수에 저장한 후 문자열의 replace 함수를 사용하여 탭(\t)을 4개의 공백으로 변경하는 코드입니다.

  1. tabto4.py를 위와 같이 변경한 후 다음과 같은 명령을 수행해 봅니다.
C:\doit>python tabto4.py a.txt b.txt
Life    is    too    short
You    need    python
  1. 이제 변경된 내용을 b.txt 파일에 저장할 수 있도록 프로그램을 변경합니다.
import sys

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

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

space_count = tab_content.replace('\t', ' '*4)

f = open(dst, 'w')
f.write(space_content)
f.close()

탭이 공백으로 변경된 space_content를 출력 파일인 dst에 쓰도록 코드를 수정하였습니다.

  1. 다음 명령 수행
C:\doit>python tabto4.py a.txt b.txt

위 명령을 수행하면 b.txt 파일이 C:\doit 디렉터리에 생성됩니다.

에디터로 b.txt 파일을 열어서 탭이 4개의 공백 문자로 변경되었는지 확인해 봅니다.



6. 하위 디럭터리 검색하기

특정 디렉터리부터 시작해서 그 하위 모든 파일 중 파이썬 파일(*.py)만 출력해 주는 프로그램을 만들려고 합니다.

이 문제가 가장 까다로웠던 것 같습니다.

  1. sub_dir_search.py 파일을 작성
def search(dirname):
	print(dirname)
    
search('c:/")

search 함수를 만들고 시작 디렉터리를 입력받도록 코드를 작성했습니다.

  1. 파일을 검색할 수 있도록 소스를 변경
import os

def search(dirname):
	filenames = os.listdir(dirname)
    	for filename in filenames:
        	full_filename = os.path.join(dirname, filename)
            	print(full_filename)
    
search('c:/")

os.listdir를 사용하면 해당 디렉터리에 있는 파일들의 리스트를 구할 수 있습니다.

여기서 구하는 파일 리스트는 파일 이름만 포함되어 있으므로 경로를 포함한 파일 이름을 구하기 위해서는 입력으로 받은 dirname을 앞에 덧붙여 주어야 합니다.

os 모듈에는 디렉터리와 파일 이름을 이어 주는 os.path.join 함수가 있으므로 이 함수를 사용하면 디렉터리를 포함한 전체 경로를 쉽게 구할 수 있습니다.

[디렉토리 출력 예]

c:/$Recycle.Bin
c:/$WINDOWS.~BT
c:/$Windows.~WS
c:/adb
c:/AMD
c:/android
c:/bootmgr
c:/BOOTNXT
… 생략 …
  1. C:/ 디렉터리에 있는 파일들 중 확장자가 .py인 파일만을 출력하도록 코드를 변경
import os

def search(dirname):
    filenames = os.listdir(dirname)
    for filename in filenames:
        full_filename = os.path.join(dirname, filename)
        ext = os.path.splitext(full_filename)[-1]
        if ext == '.py': 
            print(full_filename)

search("c:/")

파일 이름에서 확장자만 추출하기 위해 os 모듈의 os.path.splitext 함수를 사용했습니다.

os.path.splitext는 파일 이름을 확장자를 기준으로 두 부분으로 나누어 줍니다.

따라서 os.path.splitext(full_filename)[-1]은 해당 파일의 확장자 이름이 됩나다.

위 코드는 확장자 이름이 .py인 경우만을 출력하도록 작성으므로, C:/디렉터리에 파이썬 파일이 없다면 아무것도 출력되지 않습니다.

  1. 그 하위 디렉터리(sub directory)를 포함한 모든 파이썬 파일을 검색하도록 코드 변경
import os

def search(dirname):
    try:
        filenames = os.listdir(dirname)
        for filename in filenames:
            full_filename = os.path.join(dirname, filename)
            if os.path.isdir(full_filename):
                search(full_filename)
            else:
                ext = os.path.splitext(full_filename)[-1]
                if ext == '.py': 
                    print(full_filename)
    except PermissionError:
        pass

search("c:/")

try ... except PermissionError로 함수 전체를 감싼 이유는 os.listdir를 수행할 때 권한이 없는 디렉터리에 접근하더라도 프로그램이 오류로 종료되지 않고 그냥 수행되도록 하기 위해서입니다.

  • full_filename이 디렉터리인지 파일인지 구별하기 위하여 os.path.isdir 함수를 사용
  • 디렉터리일 경우 해당 경로를 입력받아 다시 search 함수를 호출
  • 해당 디렉터리의 파일이 디렉터리일 경우 다시 search 함수를 호출(재귀 호출)
  • 해당 디렉터리의 하위 파일을 다시 검색하기 시작하므로 결국 모든 파일들을 검색할 수 있게 됨

※ 재귀 호출이란 자기 자신을 다시 호출하는 프로그래밍 기법이다. 이 코드에서 보면 search 함수에서 다시 자기 자신인 search 함수를 호출하는 것이 바로 재귀 호출이다.

profile
Tistory로 이사갔어요

0개의 댓글