Python에서 파일 처리는 데이터를 영구적으로 저장하고 읽어오는 데 필수적인 기능입니다. 이번 포스팅에서는 파일을 여는 방법부터 읽기, 쓰기, 닫기, 그리고 다양한 파일 형식(CSV, JSON) 처리까지 자세히 알아보겠습니다.

 

1. 파일 열기와 닫기 

파일을 사용하려면 먼저 open() 함수를 통해 열어야 합니다. 파일을 다 사용한 후에는 close() 메서드로 닫아주는 것이 좋습니다.

 

그러나 파일을 열고 닫는 과정에서 예외가 발생할 수 있으므로, with을 사용하면 자동으로 파일을 닫아주어 안전합니다.

 

2. 파일 모드

open() 함수는 두 번째 인자로 파일 모드를 받습니다. 주요 모드는 다음과 같습니다:

'r': 읽기 모드 (파일이 존재해야 함)

'w': 쓰기 모드 (파일이 없으면 생성, 있으면 내용 삭제)

'a': 추가 모드 (파일이 없으면 생성, 있으면 내용 끝에 추가)

'b': 바이너리 모드 (예: 'rb', 'wb')

 

 바이너리 모드

Python에서 open() 함수의 모드에 'b'를 추가하면 파일이 바이너리 모드로 열립니다.

바이너리 모드는 데이터를 바이트(byte) 단위로 처리하며, 텍스트 인코딩/디코딩 과정 없이 파일의 원본 데이터 그대로를 읽거나 쓸 수 있습니다.

 

사용 이유

텍스트 파일이 아닌 이미지, 오디오, 동영상, 실행 파일 등을 처리할 때.

데이터의 원본 상태를 유지하며 읽고 써야 할 때.

텍스트가 아닌 데이터는 일반적인 텍스트 모드('r', 'w')로 처리하면 깨질 수 있습니다.

 

바이너리 모드와 주요 파일 모드의 조합

 

바이너리 모드 사용 시 주의사항

1. 텍스트와 바이너리 데이터 구분

    • 데이터가 바이트 객체(bytes)로 반환됩니다. 텍스트 데이터를 처리하려면 디코딩(decode)이 필요합니 다.

 

2. 텍스트 모드와의 차이점

    • 텍스트 모드는 문자열(str)로 데이터를 읽고 쓰며, 자동으로 인코딩/디코딩을 처리합니다.

    • 바이너리 모드는 바이트(bytes) 단위로 데이터를 처리하며, 인코딩/디코딩을 하지 않습니다.

3. 플랫폼 간 차이점

    • 텍스트 모드에서는 파일의 개행 문자(\n)가 운영 체제에 따라 변환됩니다. 바이너리 모드는 변환 없이 데이터를 그대로 처리합니다.

4. 파일 크기 확인

    • 바이너리 모드를 사용할 때는 파일 크기를 확인하거나 특정 바이트를 처리하는 데 유용합니다.

 

 

바이너리 모드가 사용되는 주요 사례

1. 이미지 및 동영상 처리:

    바이너리 데이터를 읽고 써서 이미지 파일을 복사하거나 동영상 데이터를 처리.

2. 파일 전송 및 소켓 프로그래밍:

    네트워크 프로토콜에서 파일 데이터를 바이트 단위로 전송.

3. 파일 암호화 및 압축:

    데이터의 원본 상태를 유지하면서 암호화하거나 압축 작업 수행.

 

3. 파일 읽기 : Reading a file

1) 전체 내용 읽기

 read() 메서드를 사용하여 파일의 전체 내용을 읽을 수 있습니다.

 

 

2) 한 줄씩 읽기

 readline() 메서드는 한 번 호출에 한 줄씩 읽어옵니다.

 

 

3) 모든 줄을 리스트로 읽기

 readlines() 메서드는 파일의 모든 줄을 리스트로 반환합니다.

 

 

 

4. 파일 쓰기 : Writing a file

1) 새 파일에 쓰기

쓰기 모드 'w'를 사용하면 파일에 데이터를 쓸 수 있습니다. 파일이 이미 존재하면 기존 내용을 삭제하고 새로 작성합니다.

 

2) 파일에 내용 추가하기

추가 모드 'a'를 사용하면 기존 내용에 새로운 내용을 덧붙일 수 있습니다.

 

5. 파일 위치 제어

파일 객체는 현재 읽기/쓰기 위치를 기억합니다. tell() 메서드로 현재 위치를 확인하고, seek() 메서드로 위치를 변경할 수 있습니다.

 

 

6. 다양한 파일 형식 다루기

1) CSV 파일

CSV(Comma-Separated Values) 파일은 데이터 저장에 널리 사용됩니다. Python의 csv 모듈을 사용하여 CSV 파일을 읽고 쓸 수 있  습니다.

 

 

2) JSON 파일

JSON(JavaScript Object Notation) 파일은 데이터 교환에 자주 사용됩니다. Python의 json 모듈을 사용하여 JSON 데이터를 파싱하고 생성할 수 있습니다.

 

 

7. 파일 처리 시 주의사항

 파일 닫기:

   with 문을 사용하여 파일을 자동으로 닫도록 하면 안전합니다. 파일을 직접 닫지 않아도 되므로 예외 상황에서도 자원을 효율적으로 관리     할 수 있습니다.

 예외 처리:

   파일 작업 중 예외가 발생할 가능성이 있으므로, tryexcept 블록을 사용하여 오류를 처리하세요.

 

 파일 모드 확인:

   파일 작업 전 올바른 모드를 선택하여 데이터 손실을 방지하세요. 예를 들어, 'w' 모드는 기존 내용을 삭제하고 새로 작성하므로 주의가 필     요합니다.

 

 

 

Python의 파일 처리는 데이터를 읽고 쓰는 기본적인 작업부터, CSV, JSON과 같은 구조화된 파일 형식의 처리까지 다양한 작업을 지원합니다. 파일 처리에서 중요한 점은 올바른 파일 모드의 선택예외 상황 관리입니다. 이상으로 포스팅 마치겠습니다.

 

 

 

Python의 딕셔너리(Dictionary)는 데이터를 키(key)값(value) 쌍으로 저장하는 자료형입니다. 딕셔너리는 데이터 검색, 수정, 추가, 삭제가 빠르고 간단하게 이루어질 수 있도록 설계된 자료구조로, Python 프로그래밍에서 매우 자주 사용됩니다.

 

 

0. 딕셔너리 : Dictionary

딕셔너리는 중괄호 {}를 사용하여 생성하며, 각 요소는 키와 값으로 구성됩니다.

는 고유해야 하며, 불변 객체만 사용할 수 있습니다. 은 모든 데이터 타입이 가능합니다.

 

키(key): 고유하며 불변 객체(문자열, 숫자, 튜플 등)만 사용 가능. 가변객체(리스트, 딕셔너리)는 사용 불가능.

 

값(value): 모든 데이터 타입 사용 가능하며, 중복 허용.

예제 코드

 

딕셔너리의 주요 특징

1. 키-값 쌍 저장: 각 키는 고유하며, 이를 통해 데이터를 효율적으로 검색할 수 있습니다.

2. 순서 보장: Python 3.7부터 딕셔너리는 삽입 순서를 유지합니다.

3. 가변성: 딕셔너리는 생성 후에도 수정, 추가, 삭제가 가능합니다.

4. 효율성: 키를 사용한 데이터 검색 속도가 빠릅니다.

 

 

 

1. 딕셔너리 생성 방법

1.1 기본 생성

 

 

1.2 dict() 함수 사용

 

 

1.3 빈 딕셔너리 생성

 

 

 

 

2. 딕셔너리의 키(key)와 값(value) 자세히 알아보기

1) 키(key)의 특징

불변 객체만 사용 가능: 문자열, 숫자, 튜플 사용 가능.

고유성: 딕셔너리에서 동일한 키가 여러 번 지정되면 마지막 값만 유지됩니다.

 

 

2) 값(value)의 특징

모든 데이터 타입 허용: 값으로 리스트, 딕셔너리 등 가변 객체도 가능.

중복 허용: 값은 중복될 수 있으며, 동일한 값을 여러 키에 연결 가능.

 

 

3) 키와 값의 관계

딕셔너리는 키를 사용하여 값을 빠르게 검색할 수 있는 데이터 구조.

키 존재 여부는 in 연산자를 사용해 확인 가능.

 

 

 

3. 딕셔너리 주요 메서드와 활용

1) 값 추가 및 수정

 

 

2) 값 삭제

pop(key): 지정한 키-값 삭제.

popitem(): 마지막으로 추가된 키-값 삭제.

 

 

3) 키가 존재하지 않을 경우 기본값 반환

get(key, default): 키가 없을 경우 기본값 반환.

 

 

4) 딕셔너리 병합

update(): 다른 딕셔너리의 키-값 추가 또는 업데이트.

 

 

5) 딕셔너리 키와 값 추출

keys(), values(), items() 사용.

 

 

 

4. 딕셔너리 컴프리헨션 : Dictionary Comprihension

딕셔너리 컴프리헨션을 사용하면 간단한 조건이나 규칙에 따라 딕셔너리를 생성할 수 있습니다.

 

 

5. 딕셔너리 순회

1) 기본 순회

 

 

2) 중첩된 딕셔너리 순회

 

 

 

 

6. 중첩 딕셔너리

Python에서는 딕셔너리 안에 딕셔너리를 값으로 넣을 수 있습니다. 이를 중첩 딕셔너리(Nested Dictionary)라고 합니다. 딕셔너리 내부의 값으로 또 다른 딕셔너리를 사용하면, 복잡한 계층 구조의 데이터를 효율적으로 표현하고 관리할 수 있습니다.

 

1. 중첩 딕셔너리 생성

key값으로는 가질 수 없습니다. 반드시 value 값으로 가져야합니다.

 

 

2. 중첩 딕셔너리 값 접근

키를 체인 방식으로 접근하여 내부 딕셔너리의 특정 값을 가져올 수 있습니다.

 

 

3. 중첩 딕셔너리 값 수정

내부 딕셔너리의 특정 키의 값을 수정할 수 있습니다.

 

 

4. 중첩 딕셔너리 값 추가

기존 내부 딕셔너리에 새로운 키-값 쌍을 추가하거나, 외부 딕셔너리에 새로운 내부 딕셔너리를 추가할 수 있습니다.

 

 

5. 중첩 딕셔너리 순회

for 루프를 사용하여 중첩 딕셔너리를 순회하면서 키와 값을 처리할 수 있습니다.

예제 코드

출력 결과:

 

 

6. 중첩 딕셔너리와 JSON 데이터

중첩 딕셔너리는 JSON(JavaScript Object Notation) 구조와 유사하므로, JSON 데이터를 파이썬 딕셔너리로 쉽게 변환하거나 저장할 수 있습니다.

 

 

중첩 딕셔너리 활용 사례

1. 데이터베이스: 사용자 프로필, 상품 카탈로그 등 계층적인 데이터를 저장합니다.

2. 설정 파일: 애플리케이션의 설정 값을 계층적으로 관리합니다.

3. API 응답 처리: REST API의 JSON 응답을 처리합니다.

 

 

 

7. 딕셔너리 사용 시 주의사항

1) 키로 불변 객체만 사용

리스트와 같은 가변 객체는 키로 사용할 수 없습니다. 키로는 문자열, 숫자, 튜플 사용 권장.

 

2) 중복 키 방지

동일한 키가 여러 번 사용되면 마지막 값만 유지되므로, 중복 키 추가를 방지해야 합니다.

 

3) 깊은 복사와 얕은 복사

중첩 딕셔너리를 복사할 때는 deepcopy를 사용하여 독립적으로 작업하세요.

 

4) 키 존재 여부 확인

키가 존재하지 않을 경우 get() 메서드나 in 연산자로 안전하게 접근하세요.

 

 

 

Python 딕셔너리는 데이터를 효율적으로 관리하고 처리할 수 있는 강력한 도구입니다. 다양한 메서드와 활용법을 이해하면 더 유연하고 강력한 프로그램을 작성할 수 있습니다. 이상으로 포스팅 마치겠습니다.

 

 

 

Python에서 문자열(String)은 문자들의 연속으로 구성된 데이터 타입으로, 텍스트 데이터를 처리하는 데 필수적입니다. 이번 포스팅에서는 문자열의 기본 개념과 다양한 문자열 메서드를 활용하는 방법까지 체계적으로 정리해보겠습니다.

 

 

 

0. 문자열 : Strings

문자열은 시퀀스 데이터 타입으로, 각 문자는 고유한 인덱스를 가지며, 다양한 내장 메서드를 사용해 조작할 수 있습니다. 문자열은 불변 객체이므로 직접 수정할 수 없으며, 새로운 문자열을 생성해야 합니다.

 

Python에서 문자열은 작은따옴표(')큰따옴표(")로 감싸서 생성할 수 있습니다.

여러 줄 문자열은 세 개의 작은따옴표(''') 또는 세 개의 큰따옴표(""")로 감쌉니다.

예제 코드

 

문자열의 특징

불변성(Immutability): 문자열은 한 번 생성되면 변경할 수 없습니다.

인덱싱(Indexing): 문자열의 각 문자는 인덱스를 통해 접근할 수 있습니다.

슬라이싱(Slicing): 문자열의 부분 문자열을 추출할 수 있습니다.

 

 

이스케이프 문자 (Escape Characters)

문자열 내에서 특수 문자를 삽입하거나, 줄 바꿈 등의 형식을 표현하기 위해 이스케이프 문자(Escape Characters)를 사용합니다. 이스케이프 문자는 역슬래시(\)와 특정 문자의 조합으로 구성됩니다.

 

 

 

 

1. 문자열 인덱싱과 슬라이싱

1.1 인덱싱

문자열의 각 문자는 인덱스를 사용해 접근할 수 있습니다.

양수 인덱스는 왼쪽에서 오른쪽으로, 음수 인덱스는 오른쪽에서 왼쪽으로 동작합니다.

 

 

1.2 슬라이싱

문자열의 부분 문자열을 추출하려면 슬라이싱을 사용합니다.

구문: string[start:end:step]

 

 

 

 

2. 문자열 연산

1) 문자열 연결

+ 연산자를 사용해 두 문자열을 연결합니다.

 

 

2) 문자열 반복

* 연산자를 사용해 문자열을 반복합니다.

 

 

 

 

3. 문자열 메서드

Python은 문자열 조작을 위한 다양한 내장 메서드를 제공합니다.

 

1) 문자열 분할 (Splitting Strings)

 split() 메서드는 문자열을 특정 구분자(separator)로 나누어 리스트로 반환합니다. 구분자를 지정하지 않으면 공백을 기준으로 분리합니   다.

 

 

2) 문자열 결합 (Joining Strings)

 join() 메서드는 리스트 등의 이터러블 요소를 하나의 문자열로 결합합니다.

 

 

3) 문자열 치환 (Replacing Strings)

 replace() 메서드는 문자열의 특정 부분 문자열을 다른 문자열로 교체합니다.

 

 

4) 문자열 검색 (Finding Strings)

 find() 메서드는 특정 부분 문자열이 처음 등장하는 인덱스를 반환하며, 찾지 못하면 -1을 반환합니다.

 

 

5) 문자열 포맷팅 (Formatting Strings)

 문자열 포맷팅은 템플릿을 사용해 데이터를 동적으로 문자열에 삽입할 수 있도록 도와줍니다.

 format() 메서드와 f-strings를 사용합니다.

 

 

6) 대소문자 변환

upper(): 문자열을 대문자로 변환.

lower(): 문자열을 소문자로 변환.

title(): 각 단어의 첫 문자를 대문자로 변환.

 

 

7) 공백 제거

strip(): 양쪽 공백 제거.

lstrip(): 왼쪽 공백 제거.

rstrip(): 오른쪽 공백 제거.

 

문자열 메서드 비교 요약

 

 

 

 

4. 문자열 활용 팁

1) 문자열 포함 여부 확인

 in 키워드를 사용해 특정 문자열이 포함되어 있는지 확인할 수 있습니다.

 

 

2) 문자열 길이 구하기

 len() 함수로 문자열의 길이를 구할 수 있습니다.

 

 

3) 문자열 순회

 for 반복문을 사용하여 문자열의 각 문자를 순회할 수 있습니다.

예제 코드

출력 결과:

 

 

5. 문자열 사용 시 주의할 점

1) 불변성: 문자열은 불변 객체이므로 수정이 불가능하며, 변경 작업은 항상 새로운 문자열을 생성합니다.

 

2) 인덱스 오류: 잘못된 인덱스에 접근하면 IndexError가 발생합니다. 인덱스를 확인하고 사용하세요.


3) 공백 처리: 입력값에서 공백은 의도치 않은 결과를 초래할 수 있으므로 strip()을 사용해 처리하는 것이 좋습니다.

 

 

Python 문자열은 텍스트 데이터 처리와 조작에서 필수적인 도구입니다. 주요 메서드와 활용 방법을 숙지하면 더욱 효율적인 코드를 작성할 수 있습니다. 이상으로 포스팅 마치겠습니다.

 

 

 

 

 

Python의 반복문은 특정 코드를 여러 번 실행할 수 있게 해주는 강력한 도구입니다. for문과 while문은 각각 다른 용도로 사용되며, 반복 제어를 통해 다양한 작업을 수행할 수 있습니다. 이번 포스팅에서는 Python의 반복문 기본 구조와 활용법, 주의할 점까지 상세히 살펴보겠습니다.

 

 

0. 반복문의 기본 개념

반복문은 코드를 여러 번 실행하기 위한 구조입니다. Python에서는 forwhile이 주로 사용되며, 각 반복문은 동작 방식이 다릅니다.

 

for

시퀀스(Sequence)의 각 요소를 순차적으로 처리합니다.

반복 횟수가 명확히 정해진 경우 적합합니다.

예: 리스트, 튜플, 문자열, range() 등.

 

while

조건이 참(True)인 동안 반복 실행합니다.

반복 횟수가 조건에 따라 달라지는 경우 적합합니다.

 

 

1. for 반복문

기본 구조

for 문은 시퀀스(예: 리스트, 문자열)의 각 요소를 순회하며 코드를 실행합니다. 반복 대상이 명확한 경우 가장 적합한 반복문입니다.

 

for 문 동작 방식

1. Python의 for은 반복 대상(리스트, 문자열 등)에서 첫 번째 요소를 가져옵니다.

2. 해당 요소를 반복 변수에 저장합니다.

3. 저장된 값을 이용해 코드 블록을 실행합니다.

4. 다음 요소로 이동하여 과정을 반복합니다.

5. 반복 대상의 모든 요소를 처리하면 반복문이 종료됩니다.

 

 

예제 1: 리스트 순회

 

출력 결과:

 

 

예제 2: 범위 순회

range() 함수와 함께 사용하여 일정 범위의 숫자를 순회할 수 있습니다.

 

출력 결과:

 

 

 

2. while 반복문

기본 구조

while 반복문은 조건이 참(True)인 동안 계속해서 코드를 실행합니다.

 

while 문 동작 방식

1. 조건식을 평가하여 참(True)이면 코드 블록을 실행합니다.

2. 실행이 끝난 후 조건식을 다시 평가합니다.

3. 조건이 거짓(False)이 되면 반복문이 종료됩니다.

 

 

예제 : 숫자 카운트 다운

 

출력 결과:

 

 

 

3. 반복 제어문 : Break & Continue

3.1 break 문

break 문은 반복문을 즉시 종료합니다.

예제 코드

 

출력 결과:

 

 

3.2 continue 문

continue 문은 현재 반복을 건너뛰고 다음 반복을 진행합니다.

예제 코드

 

출력 결과:

 

 

 

4. 반복문 활용 팁

 

4.1 else 절과 함께 사용하기

 

반복문과 else 절을 함께 사용하여 반복이 정상적으로 종료된 후 실행될 코드를 지정할 수 있습니다.

예제 코드

출력 결과:

 

 

4.2 중첩 반복문

 

반복문 안에 또 다른 반복문을 포함하여 2차원 데이터 등을 처리할 수 있습니다.

예제 코드

출력 결과:

 

 

 

4.3 리스트 내포(List Comprehension)

 

리스트 내포를 사용하면 간결하고 효율적으로 리스트를 생성할 수 있습니다.

 

예제 1 : 

 

출력 결과:

 

 

예제 2:

 

출력 결과:

 

 

 

5. 반복문 사용 시 주의할 점

• 반복 횟수 확인

   반복 횟수가 너무 많아지거나 조건을 잘못 설정하면 성능 저하가 발생할 수 있습니다.

 

• 무한 루프 방지

   특히 while 문을 사용할 때 종료 조건을 명확히 설정해야 합니다.

 

• 가독성 유지

   중첩된 반복문은 가독성을 떨어뜨릴 수 있습니다. 필요하면 함수를 사용해 코드 블록을 분리하세요.

 

• 적절한 반복문 선택

   정해진 범위를 순회하는 경우에는 for 문, 조건에 따라 반복이 필요한 경우에는 while 문을 사용하는 것이 적합합니다.

 

 

 

 

Python의 반복문은 단순한 작업부터 복잡한 데이터 처리까지 다양한 작업을 효율적으로 수행할 수 있습니다. for 문과 while 문, 그리고 반복 제어문(break, continue)을 잘 활용하면 더욱 간결하고 효율적인 코드를 작성할 수 있습니다. 이상으로 포스팅 마치겠습니다.

Python에서 리스트(list)는 여러 요소를 하나의 변수에 저장할 수 있는 시퀀스 데이터 타입입니다. 리스트는 가변적(mutable)이며, 다양한 데이터 타입을 포함할 수 있어 데이터 관리에 매우 유용합니다. 이번 포스팅에서는 Python 리스트의 생성 방법부터 다양한 활용법까지 살펴보겠습니다.

 

 

0. 리스트 : List

리스트(List)는 시퀀스 데이터 타입의 하나로, 요소를 순서대로 저장할 수 있습니다.

각 요소는 고유한 인덱스를 가지며, 이를 통해 요소에 접근할 수 있습니다.

 

리스트의 특징

순서가 있음(Order): 리스트는 입력된 순서를 유지합니다.

다양한 데이터 타입: 문자열, 숫자, 불리언, 객체 등 모든 데이터 타입을 포함할 수 있습니다.

중복 허용: 동일한 값을 여러 번 포함할 수 있습니다.

가변성(Mutability): 요소의 추가, 삭제, 수정이 가능합니다.

 

 

1. 리스트 생성하기

리스트는 대괄호 []를 사용하여 생성하며, list() 함수를 사용할 수 있습니다.

각 요소는 쉼표 ,로 구분합니다.

또한, list() 함수를 사용하여 다른 이터러블(iterable) 객체를 리스트로 변환할 수 있습니다.

 

 

1.1 대괄호를 사용한 리스트

 

 

1.2 빈 리스트 생성

 

 

1.3 list() 함수를 사용한 리스트

 

 

1.4 문자열이나 튜플을 리스트로 변환

 

Tip : 리스트는 중첩이 가능하며, 리스트 안에 리스트를 넣을 수도 있습니다.

 

요소의 데이터 타입이 달라도 동작하지만, 일관된 데이터 타입을 유지하는 것이 가독성과 관리에 유리합니다.

 

 

 

 

 

2. 리스트 인덱싱과 슬라이싱 : List Indexing and Slicing

 

인덱싱 (Indexing)

 

리스트의 각 요소는 인덱스를 통해 접근할 수 있습니다.

인덱스는 0부터 시작합니다.

음수 인덱스를 사용하면 리스트의 뒤에서부터 접근할 수 있습니다.

 

 

슬라이싱 (Slicing)

 

슬라이싱은 리스트의 부분 집합을 반환합니다.

 

구문: list[start:end:step]

start: 시작 인덱스(포함)

end: 종료 인덱스(포함하지 않음)

step: 간격 (기본값은 1)

 

 

Tip : 슬라이싱 결과는 새로운 리스트로 반환됩니다. 원본 리스트는 변경되지 않습니다.

 

간격(step)을 음수로 설정하면 리스트를 역순으로 반환할 수 있습니다.

예제 코드

출력 결과:

 

 

Tip : 슬라이싱 범위를 초과해도 오류가 발생하지 않고, 가능한 부분만 반환됩니다.

예제 코드

출력 결과:

 

 

 

 

3. 리스트 수정하기

리스트는 가변적(mutable)이므로, 요소의 추가, 수정, 삭제가 가능합니다.

 

3.1 요소 추가

append(): 리스트의 끝에 요소를 추가합니다.

 

 

insert(): 지정한 인덱스 위치에 요소를 추가합니다.

 

 

extend(): 다른 리스트의 모든 요소를 기존 리스트에 추가합니다.

 

 

 

3.2 요소 수정

특정 인덱스의 값을 직접 할당하여 수정할 수 있습니다.

 

 

 

3.3 요소 삭제

remove(): 지정한 값을 가진 첫 번째 요소를 삭제합니다.

 

 

pop(): 지정한 인덱스의 요소를 삭제하고, 그 값을 반환합니다. 인덱스를 지정하지 않으면 마지막 요소를 삭제합니다.

 

 

del 키워드: 특정 인덱스의 요소를 삭제하거나, 슬라이싱을 통해 여러 요소를 삭제할 수 있습니다.

 

 

clear(): 리스트의 모든 요소를 삭제하여 빈 리스트로 만듭니다.

 

 

 

주의할 점

 

remove()pop()의 차이: remove()는 값을 삭제하고, pop()은 인덱스를 지정해 삭제합니다.

슬라이싱으로 삭제: del 키워드를 사용할 때 슬라이싱을 통해 범위를 삭제하면 범위 내 모든 요소가 삭제됩니다.

 

 

 

4. 리스트 탐색 및 활용

4.1 탐색

in 키워드를 사용하여 리스트에 특정 요소가 있는지 확인할 수 있습니다.

 

 

특정 값의 인덱스 반환

 

 

 

4.2 정렬

• sort(): 리스트를 오름차순으로 정렬합니다. (기본적으로 원본 리스트가 수정됩니다)

 

 

• reverse(): 리스트의 순서를 역순으로 뒤집습니다.

 

 

 

 

5. 리스트 내포 : List Comprehension

리스트 내포는 간결하고 효율적으로 새로운 리스트를 생성하는 Python 고유의 문법입니다.

 

구문

 

예제

(1) 1부터 10까지의 제곱수 생성

 

(2) 짝수만 필터링

 

 

 

 

 

6. 2차원 리스트 : Two-Dimentional (2D) Lists

Python 리스트는 중첩이 가능하므로, 2차원 리스트를 사용하여 행과 열 형태의 데이터를 저장하고 관리할 수 있습니다. 이를 통해 행렬(matrix) 또는 표 구조 데이터를 표현할 수 있습니다.

 

 

• 2차원 리스트 생성

 2차원 리스트는 리스트 안에 리스트를 요소로 포함한 구조로 생성됩니다.

 

 

 

• 2차원 리스트 요소 접근

 2차원 리스트의 요소는 행(row)열(column)의 인덱스를 사용하여 접근할 수 있습니다.

 • 구문: list[row][column]

 

 

• 2차원 리스트 요소 수정

 2차원 리스트는 특정 요소를 직접 수정할 수 있습니다.

 

 

• 2차원 리스트 순회

 2차원 리스트는 중첩된 for 문을 사용하여 모든 요소를 순회할 수 있습니다.

예제 코드

출력 결과:

 

 

리스트 내포를 사용한 2차원 리스트 생성

 리스트 내포(List Comprehension)를 사용하여 2차원 리스트를 간결하게 생성할 수 있습니다.

예제 코드

출력 결과:

 

 

 

2차원 리스트에서 특정 열 추출

 2차원 리스트에서 특정 열을 추출하려면 리스트 내포를 사용합니다.

 

 

 

2차원 리스트로 전치 행렬 만들기

 전치 행렬(Transpose)을 구하려면 zip() 함수와 리스트 내포를 조합하여 사용할 수 있습니다.

예제 코드

출력 결과:

 

 

주의할 점

1. 인덱스 유효성:

    인덱스가 리스트 범위를 초과하면 IndexError가 발생합니다. 항상 인덱스를 확인하세요.

 

 

2. 가변 객체의 참조:

     리스트 안의 리스트는 참조로 저장되므로, 한 행의 변경이 원치 않는 영향을 미칠 수 있습니다.

 

 

3. 비정형 리스트:

     2차원 리스트의 각 행의 길이가 다를 수 있습니다. 작업 전에 각 행의 길이를 확인하는 것이 중요합니다.

 

 

7. 리스트 활용 

 

리스트 병합

+ 연산자로 두 리스트를 병합할 수 있습니다.

예제 코드

출력 결과:

 

 

리스트 반복

* 연산자로 리스트를 반복할 수 있습니다.

예쩨 코드

출력 결과:

 

 

 

 

 

Python의 리스트는 강력하면서도 유연한 데이터 타입으로, 다양한 데이터 처리 작업에 사용됩니다. 리스트의 생성, 수정, 탐색, 정렬, 고급 활용(List Comprehension)까지 Python 리스트의 모든 기능을 잘 활용한다면 더욱 효율적인 코드를 작성할 수 있습니다. 이상으로 포스팅 마치겠습니다.

Python의 제어 흐름(Control Flow)은 프로그램이 명령문을 실행하는 순서를 결정하는 핵심 개념입니다.

이를 통해 조건에 따라 특정 코드 블록을 실행하거나, 논리적 판단에 따라 다른 실행 경로를 선택하며, 효율적인 프로그램을 작성할 수 있습니다. 이번 포스팅에서는 Python의 주요 제어 흐름 요소를 예제와 함께 살펴보겠습니다.

 

 

1. 불리언 표현식 : Boolean Expressions

불리언(Boolean)참(True) 또는 거짓(False) 두 가지 값만을 가지는 데이터 타입입니다.

불리언 표현식은 이러한 불리언 값을 반환하는 조건식으로, 제어 흐름의 기반이 됩니다. 조건문에서 사용되어 코드 실행 여부를 결정합니다.

 

불리언 표현식의 특징

불리언 값은 bool 타입을 가집니다.

조건문의 평가 결과는 항상 불리언 값으로 반환됩니다.

비교 연산자논리 연산자를 사용하여 불리언 표현식을 생성할 수 있습니다.

 

예제: bool()로 값 평가하기

 

설명: Python에서는 숫자 0, 빈 문자열(""), 빈 리스트([]) 등은 **거짓(False)**로 평가되며, 그 외의 값은 **참(True)**으로 평가됩니다.

 

 

 

2. 관계 연산자 : Relational Operators

관계 연산자는 두 값을 비교하여 불리언 값을 반환합니다. Python에서는 다음과 같은 관계 연산자를 사용합니다: 

관계 연산자

관계 연산자는 조건문의 기본적인 판단 요소로 활용되며, 다른 연산자와 함께 사용하면 복잡한 조건도 처리할 수 있습니다.

 

예제: 학생 성적 평가

 

출력 결과:

 

 

 

 

3. 논리 연산자 : Logical Operators

논리 연산자는 불리언 값들을 조합하여 새로운 불리언 값을 반환합니다. 논리 연산자는 복잡한 조건을 처리하거나, 여러 조건을 결합하여 평가할 때 사용됩니다. Python의 주요 논리 연산자는 다음과 같습니다.

 

3.1 and 연산자

 두 조건이 모두 참(True)일 때만 참(True)을 반환합니다.

 

 

3.2 or 연산자

 두 조건 중 하나라도 참(True)이면 참(True)을 반환합니다.

 

 

3.3 not 연산자

 조건의 값을 반전시켜, 참(True)은 거짓(False)으로, 거짓(False)은 참(True)으로 반환합니다.

 

 

예제: 논리 연산자 사용하기

 

출력 결과:

 

 

 

 

4. 조건문 : Conditional Statements

조건문은 특정 조건에 따라 코드 블록의 실행 여부를 결정합니다. Python에서는 if, elif, else 키워드를 사용하여 조건문을 구성합니다.

 

4.1 if 문

 if 문은 조건이 **참(True)**일 때 해당 코드 블록을 실행합니다.

 

예제 코드

출력 결과:

 

 

4.2 else 문

 else 문은 앞선 if 조건이 **거짓(False)**일 때 실행될 코드 블록을 정의합니다.

 

예제 코드

출력 결과:

 

 

4.3 elif 문

 elif 문은 추가적인 조건을 검사할 때 사용하며, 첫 번째 조건이 거짓이고, elif 조건이 참일 경우 해당 코드 블록을 실행합니다.

 

예제 코드

출력 결과:

 

 

5. 진리값 평가 : Truth Value Testing

Python에서는 불리언이 아닌 값도 조건문에서 참(True) 또는 거짓(False)으로 평가될 수 있습니다. 일반적으로 다음과 같이 평가됩니다:

 

거짓으로 평가되는 값:

None

False

숫자형의 0 값 (예: 0, 0.0)

빈 시퀀스 (예: '', [], ())

빈 딕셔너리 {}

 

참으로 평가되는 값:

위에 언급되지 않은 모든 값

 

예제: 리스트 평가

 

출력 결과:

 

 

 

6. 삼항 연산자 : Ternary Operator

Python에서는 삼항 연산자를 사용하여 한 줄로 조건에 따른 값을 반환할 수 있습니다.

 

 

예제: 양수와 음수 판별

 

출력 결과:

 

 

 

7. pass 문

pass은 아무 동작도 하지 않는 문장으로, 코드 구조를 유지하거나, 실행이 필요한 위치를 임시로 채우는 데 사용됩니다.

 

pass 문 사용 방법

1. 코드 설계 중 사용: 나중에 구현할 로직의 자리표시자로 사용합니다.

2. 조건문에서의 사용: 특정 조건에서 아무 작업도 하지 않도록 설정합니다.

3. 반복문에서의 사용: 특정 반복을 무시하면서 전체 반복을 유지합니다.

4. 예외 처리에서의 사용: 특정 예외를 처리하지 않고 무시할 때 사용됩니다.

 

주의 사항

pass 문은 프로그램 실행에 아무런 영향을 미치지 않으므로, 최종 코드에서는 반드시 필요한 로직으로 대체해야 합니다.

조건문이나 반복문에서 pass를 사용할 때, 항상 주석을 통해 그 의도를 명확히 표현해야 합니다.

 

함수를 설계할 때 구체적인 구현 없이 함수 이름과 구조만 먼저 정의하고 싶을 때 사용할 수도 있습니다.

예제: 미완성 함수

 

출력 결과:

 

 

8. 예외 처리 : Exception Handling

프로그램 실행 중 발생할 수 있는 오류를 처리하기 위해 try, except, finally 블록을 사용합니다. 이를 통해 프로그램이 예기치 않게 종료되는 것을 방지하고, 오류 상황을 처리할 수 있습니다.

 

예외 처리 구성 요소

1. try 블록: 오류가 발생할 수 있는 코드를 실행합니다.

2. except 블록: 발생한 오류를 처리합니다.

3. finally 블록: 오류 발생 여부와 관계없이 항상 실행됩니다.

 

예외 처리 시 주의 사항

발생한 오류를 무조건 무시하지 말고, 상황에 맞는 대체 동작을 구현해야 합니다.

필요할 경우 로그를 남겨 디버깅에 활용합니다.

 

예제: 0으로 나누기 예외 처리

 

출력 결과:

 

 

 

 

Python의 제어 흐름은 프로그램의 논리적 구조를 구성하는 데 필수적입니다. 이를 통해 조건에 따라 코드 블록을 실행하고, 오류를 관리하며, 복잡한 조건을 간결하게 표현할 수 있습니다. 특히, pass 문은 설계 단계에서 코드 구조를 유지하는 데 유용하지만, 필요 이상으로 남용하지 않도록 주의해야 합니다. 이상으로 이번 포스팅을 마치겠습니다.

Python에서 함수는 코드의 재사용성과 구조를 개선하는 가장 기본적이고 강력한 도구입니다. 이번 포스팅에서는 함수의 정의와 호출, 함수의 종류(Built-in Functions와 User-defined Functions), 매개변수와 반환값, 스코프(Scope), 네임스페이스(Namespace), 람다 함수, 재귀 함수까지 Python 함수의 핵심 개념을 살펴보겠습니다.

 

 

0.  함수 : Function

'함수(Function)'는 특정 작업을 수행하도록 설계된 코드의 집합입니다. 함수는 입력(매개변수)을 받아 특정 작업을 수행한 뒤 결과(반환값)를 출력할 수 있습니다. 이를 통해 코드의 중복을 줄이고 가독성을 높이며 유지보수를 용이하게 만듭니다.

 

Python에서 함수는 크게 Built-in FunctionsUser-defined Functions로 나뉩니다.

 

(1) Built-in Functions

 

Built-in Functions는 Python에서 기본적으로 제공하는 함수들로, 추가적인 설치나 정의 없이 바로 사용할 수 있습니다. 이들은 대부분 자주 사용되는 기능을 포함하며, Python 코드의 효율성을 높이는 데 중요한 역할을 합니다.

데이터 타입 변환: int(), float(), str()

수학 연산: abs(), pow(), round()

문자열 처리: len(), format()

컬렉션 처리: sum(), max(), min(), sorted()

기타 유용한 기능: print(), input(), type()

 

Built-in Functions는 Python의 기본 동작을 이해하고 활용하는 데 중요한 기반을 제공합니다.

 

(2) User-defined Functions

 

User-defined Functions는 사용자가 특정 작업을 수행하기 위해 직접 정의한 함수입니다. 함수는 def 키워드를 사용해 정의하며, 입력과 출력을 자유롭게 설계할 수 있습니다. 이러한 사용자 정의 함수는 특정 상황에 맞는 맞춤형 기능을 제공합니다.

 

 

1. 함수 정의 및 호출 : Defining and Calling a Function

1.1 함수 정의 (Defining)

함수는 def 키워드를 사용하여 정의하며, 함수 이름, 괄호 안의 매개변수, 함수 본문으로 구성됩니다. 

함수 이름은 의미를 명확히 나타내야 합니다.

괄호 안에 매개변수를 지정해 입력값을 받을 수 있습니다.

return 키워드를 사용해 값을 반환할 수 있습니다.

 

예제: 두 수의 합을 계산하는 함수

 

1.2 함수 호출 (Calling)

정의된 함수는 함수 이름과 괄호 안에 인수를 전달하여 호출합니다.

예제 코드

출력 결과:

 

 

2. 매개변수와 인수 : Parameters & Arguments

매개변수는 함수 정의 시 사용되며, 호출 시 인수를 통해 값이 전달됩니다.

 

매개변수(Parameter)

매개변수는 함수 정의 시 입력값을 받을 변수입니다. 함수 호출 시 입력값(인수)이 매개변수에 전달됩니다. Python에서는 다양한 형태의 매개변수를 지원합니다.

 

• 위치 매개변수 (Positional Parameter): 함수 호출 시 입력값이 정의된 순서대로 매개변수에 전달됩니다.

• 기본값 매개변수 (Default Parameter): 매개변수에 기본값을 설정하면, 호출 시 해당 인수를 생략할 수 있습니다.

• 키워드 매개변수 (Keyword Parameter): 함수 호출 시 매개변수 이름을 명시적으로 지정해 전달합니다.

• 가변 매개변수 (Variable-length Parameter): 매개변수의 개수가 가변적인 경우 사용됩니다.

  - *args: 위치 인수를 여러 개 받을 수 있는 매개변수.

  - **kwargs: 키워드 인수를 여러 개 받을 수 있는 매개변수.

 

인수(Argument)

인수는 함수 호출 시 함수에 실제로 전달되는 값입니다. 매개변수와 인수는 함수 호출 과정에서 짝을 이루며 동작합니다.

 

  위치 인수 (Positional Argument): 함수 호출 시 매개변수의 순서에 따라 전달됩니다.

  키워드 인수 (Keyword Argument): 호출 시 매개변수 이름을 명시적으로 지정하여 전달됩니다.

  가변 인수 (Variable-length Argument): 인수의 개수가 변동적인 경우 사용할 수 있습니다.

 

2.1 위치 매개변수 (Positional Parameter)

함수 호출 시 인수는 정의된 매개변수의 순서에 따라 전달됩니다.

예제 코드

출력 결과:

 

2.2 기본 매개변수 값 (Default Parameter)

매개변수에 기본값을 설정하여 함수 호출 시 해당 인수를 생략할 수 있습니다.

예제 코드

출력 결과:

 

2.3 키워드 인수 (Keyword Argument)

함수 호출 시 매개변수 이름을 명시하여 인수를 전달할 수 있습니다.

예제 코드

출력 결과:

 

 

3. 반환값 : Return value

반환값은 함수가 작업을 수행한 결과를 함수 호출자에게 전달하는 값입니다. 반환값은 return 키워드를 사용해 정의합니다.

 

반환값의 특징

함수는 하나의 반환값만 가질 수 있지만, 다수의 값을 튜플 형태로 반환할 수 있습니다.

 

예제: 두 수의 곱과 합을 반환하는 함수

 

출력 결과:

 

 

Tip: 반환값이 없는 함수는 None을 반환합니다.

예제 코드

출력 결과:

 

 

4. 스코프와 네임스페이스 : Scope and Namespace

 

Python에서는 스코프(Scope)네임스페이스(Namespace)가 변수와 함수의 접근 및 가시성을 결정합니다. 

 

스코프(Scope)

 

스코프는 변수가 유효한 코드의 범위를 의미합니다. Python은 LEGB 규칙(Local, Enclosing, Global, Built-in)을 통해 변수를 검색합니다.

로컬 스코프(Local Scope): 함수 내부에서 생성된 변수.

전역 스코프(Global Scope): 함수 외부에서 선언된 변수.

비내부적 로컬 스코프(Enclosing Scope): 중첩 함수의 외부 함수에서 생성된 변수.

내장 스코프(Built-in Scope): Python의 기본 제공 함수와 객체.

 

네임스페이스(Namespace)

 

네임스페이스는 이름과 객체를 매핑하는 저장 공간으로, 이름 충돌을 방지하고 변수 관리를 체계적으로 합니다.

Local Namespace: 함수 내부의 변수.

Global Namespace: 모듈 수준의 변수.

Built-in Namespace: Python 내장 함수 및 객체.

 

4.1 지역 변수 (Local Variable)

함수 내에서 정의된 변수는 지역 변수로, 함수 내부에서만 접근 가능합니다.

예제 코드

출력 결과:

 

4.2 전역 변수 (Global Variable)

함수 외부에서 정의된 변수는 전역 변수로, 함수 내부에서도 접근할 수 있습니다.

예제 코드

출력 결과:

 

 

4.3 전역 변수 수정

함수 내부에서 전역 변수를 수정하려면 global 키워드를 사용해야 합니다.

예제 코드

출력 결과:

 

 

 

5. 람다 함수 : Lambda

람다 함수는 익명 함수(Anonymous Function)라고도 하며, lambda 키워드를 사용해 간단한 함수를 한 줄로 정의할 수 있습니다.

단일 표현식을 기반으로 하며, 코드의 간결성을 높이는 데 유용합니다. 

 

5.1 람다 함수 기본 구조

 

람다 함수는 주로 다른 함수와 함께 사용되며, 간단한 계산이나 데이터 처리를 위해 활용됩니다.

 

5.2 활용 예제

(1) 기본 람다 함수

 

 

(2) map() 함수와 람다

 

 

(3) filter() 함수와 람다

 

 

(4) sorted() 함수와 람다

 

 

6. 재귀 함수 : Recursive Function

재귀 함수는 자기 자신을 호출하는 함수입니다. 이를 통해 복잡한 문제를 간결하게 해결할 수 있지만, 종료 조건을 반드시 설정해야 무한 루프와 스택 오버플로우를 방지할 수 있습니다.

 

예제: 팩토리얼 계산

 

출력 결과:

 

 

 

주의: 재귀 호출이 너무 깊어지면 RecursionError가 발생할 수 있습니다.

->

재귀 호출이 너무 깊어진다는 말은, 재귀 함수가 자기 자신을 호출하는 과정이 반복되면서 호출 스택(Call Stack)이 한계치를 초과하게 되는 상황을 의미합니다. 이를 무한 재귀 호출 또는 재귀 깊이 초과라고도 합니다.

 

 

재귀 함수는 자기 자신을 호출하기 때문에 함수가 끝나기 전에 새로운 호출이 계속해서 스택에 추가됩니다.

하지만 Python에는 스택의 최대 깊이가 제한되어 있습니다. 기본적으로 이 깊이를 초과하면 RecursionError가 발생합니다.

 

예제: 종료 조건이 없는 재귀 함수

이 코드는 종료 조건 없이 자기 자신을 계속 호출합니다. 결과적으로 스택이 초과되어 아래와 같은 오류가 발생합니다.

 

출력 결과:

 

Python에서는 기본 최대 재귀 깊이가 약 1000번으로 설정되어 있습니다. 이 값은 sys 모듈의 sys.getrecursionlimit() 함수를 사용해 확인할 수 있습니다.

 

sys.setrecursionlimit()을 사용하면 재귀 깊이를 변경할 수 있지만, 값이 너무 크면 메모리 문제가 발생할 수 있으니 주의해야 합니다.

 

재귀 깊이 초과를 방지하는 방법에는 종료 조건을 추가하거나, 반복문으로 변환하는 것 입니다.

반복문은 호출 스택을 사용하지 않으므로 메모리 초과 문제를 방지할 수 있습니다.

재귀 함수
반복문

 

 

 

이번 포스팅에서는 Python 함수의 다양한 측면을 살펴보았습니다. Built-in Functions를 활용하면 기본적인 작업을 효율적으로 수행할 수 있으며, User-defined Functions는 특정 상황에 맞는 맞춤형 기능을 제공합니다. 또한, 스코프와 네임스페이스를 이해하면 코드의 가독성과 안정성을 높일 수 있습니다.

이상으로 포스팅 마치겠습니다.

Python은 배우기 쉽고 강력한 프로그래밍 언어입니다. 이번 포스팅에서는 Python의 기본 문법, 변수 타입, print() 함수, 에러 처리, 숫자 연산, 문자열 다루기 등을 자세히 정리해보겠습니다.

 

1. Python Syntax: 기본 개념

Python의 문법은 코드 작성 방식을 의미하며, 다른 프로그래밍 언어와 비교했을 때 더 간결하고 읽기 쉽습니다.

필자는 C와 C++를 공부를 먼저 공부하였는데, 파이썬에서 훨씬 간편함과 편리함을 느꼈습니다.

 

Python은 다음과 같은 특징을 가진 언어입니다:

간결하고 읽기 쉬운 코드: 들여쓰기를 통해 코드 블록을 구분합니다.

동적 타이핑: 변수를 선언할 때 타입을 명시하지 않아도 됩니다.

강력한 표준 라이브러리: 기본 제공 함수와 모듈이 풍부합니다.

 

1.1 기본 문법 (Syntax)

들여쓰기(Indentation): 중괄호 {} 대신 들여쓰기로 코드 블록을 정의합니다.

 

세미콜론(;) 필요 없음: Python은 각 명령어 뒤에 세미콜론을 요구하지 않습니다.

 

1.2 print() 함수

Python에서 print()는 데이터를 출력하는 가장 기본적인 함수입니다.

예제 코드

출력 결과:

 

2. 변수와 데이터 유형 (Variable Types)

변수는 데이터를 저장하는 이름표입니다. Python은 데이터 유형을 명시하지 않고 값을 할당하면 자동으로 유형이 결정됩니다.

 

2.1 변수 선언 및 규칙

Python에서는 변수를 선언할 때 타입을 지정하지 않아도 됩니다.

변수를 선언하려면 이름을 지정하고 값을 할당합니다.

 

변수명 규칙

1. 문자, 숫자, 밑줄(_)만 사용 가능.

2. 숫자로 시작할 수 없음.

3. 대소문자를 구분함 (예: name Name은 다른 변수).

 

변수 타입 확인

type() 함수를 사용해 변수의 타입을 확인할 수 있습니다.

예제 코드

출력 결과:

 

2.2 데이터 유형

Python에서 자주 사용하는 기본 데이터 유형은 다음과 같습니다.

정수(int): 정수를 저장.

 

부동소수점(float): 실수 값을 저장.

 

문자열(str): 텍스트 데이터를 저장.

 

불리언(bool): 참(True) 또는 거짓(False)을 나타냄.

 

3. Python의 숫자 연산

Python은 다양한 수학 연산을 지원하며, 숫자와 관련된 여러 기능이 내장되어 있습니다.

 

3.1 숫자 전환 (Changing Numbers)

Python에서는 정수와 실수를 서로 변환할 수 있습니다.

예제 코드

출력 결과:

 

3.2 지수 표현 (Exponents)

** 연산자를 사용해 거듭제곱을 계산합니다.

 

3.3 나머지 계산 (Modulo)

% 연산자는 나머지를 계산합니다.

 

3.4 기본 연산자

아래는 기본적으로 쓰이는 python 기본 연산자들 입니다.

 

4. 문자열 연산

4.1 문자열 연결 (Concatenation)

+ 연산자를 사용해 문자열을 연결할 수 있습니다.

 

4.2 += 연산자 (Plus Equals)

+= 연산자를 사용하면 기존 문자열에 새로운 문자열을 쉽게 추가할 수 있습니다.

 

4.3 멀티라인 문자열 (Multi-line Strings)

""" 또는 '''를 사용하면 여러 줄의 문자열을 표현할 수 있습니다.

예제 코드

출력 결과:

 

5. Python의 오류 (Errors)

5.1 Syntax Error (문법 오류)

Python 문법에 맞지 않는 코드를 작성하면 발생합니다.

예제 코드

오류 메세지:

 

5.2 Name Error (이름 오류)

정의되지 않은 변수나 함수를 참조할 때 발생합니다.

예제 코드

오류 메세지:

 

6. 실습 예제

 

이상으로 포스팅 마치겠습니다.

+ Recent posts