Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 | 31 |
Tags
- 세션저장소
- 서비스 메시
- 보안
- 마이크로서비스
- 인메모리데이터베이스
- 컨테이너오케스트레이션
- 고가용성
- 메시징 패턴
- kubernetes
- 분산 모니터링
- 모노리스 분해
- 분산 시스템
- 클라우드
- ApacheBench
- 이벤트 스트리밍
- 모니터링
- 메시지 브로커
- 클러스터
- devops
- Kafka 클러스터
- 프로덕션 운영
- docker
- Python
- 서비스 설계
- 마이크로서비스 운영
- RabbitMQ Exchange
- infrastructureascode
- 마이크로서비스 통신
- rabbitmq
- CI/CD
Archives
- Today
- Total
hobokai 님의 블로그
Python 완전 정복 가이드 - 2편: 중급편 본문
Python 완전 정복 가이드 - 2편: 중급편
목차
객체지향 프로그래밍
클래스와 객체
# 기본 클래스 정의
class Person:
# 클래스 변수 (모든 인스턴스가 공유)
species = "Homo sapiens"
# 생성자 메서드
def __init__(self, name, age):
# 인스턴스 변수
self.name = name
self.age = age
# 인스턴스 메서드
def introduce(self):
return f"안녕하세요, 저는 {self.name}이고 {self.age}세입니다."
# 인스턴스 메서드
def have_birthday(self):
self.age += 1
print(f"{self.name}님이 {self.age}세가 되었습니다!")
# 객체 생성과 사용
person1 = Person("Alice", 25)
person2 = Person("Bob", 30)
print(person1.introduce()) # 안녕하세요, 저는 Alice이고 25세입니다.
person1.have_birthday() # Alice님이 26세가 되었습니다!
# 클래스 변수 접근
print(Person.species) # Homo sapiens
print(person1.species) # Homo sapiens
메서드의 종류
class MathUtils:
pi = 3.14159
def __init__(self, name):
self.name = name
# 인스턴스 메서드
def instance_method(self):
return f"인스턴스 메서드: {self.name}"
# 클래스 메서드
@classmethod
def class_method(cls):
return f"클래스 메서드: {cls.pi}"
# 정적 메서드
@staticmethod
def static_method(x, y):
return x + y
# 사용 예시
math_util = MathUtils("계산기")
print(math_util.instance_method()) # 인스턴스 메서드: 계산기
print(MathUtils.class_method()) # 클래스 메서드: 3.14159
print(MathUtils.static_method(5, 3)) # 8
상속 (Inheritance)
# 부모 클래스
class Animal:
def __init__(self, name, species):
self.name = name
self.species = species
def make_sound(self):
return "동물이 소리를 냅니다"
def info(self):
return f"{self.name}은(는) {self.species}입니다"
# 자식 클래스
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name, "개") # 부모 클래스 생성자 호출
self.breed = breed
# 메서드 오버라이딩
def make_sound(self):
return "멍멍!"
# 새로운 메서드 추가
def fetch(self):
return f"{self.name}이(가) 공을 가져옵니다"
class Cat(Animal):
def __init__(self, name, color):
super().__init__(name, "고양이")
self.color = color
def make_sound(self):
return "야옹!"
def climb_tree(self):
return f"{self.name}이(가) 나무에 올라갑니다"
# 사용 예시
dog = Dog("멍멍이", "골든 리트리버")
cat = Cat("나비", "검은색")
print(dog.info()) # 멍멍이은(는) 개입니다
print(dog.make_sound()) # 멍멍!
print(dog.fetch()) # 멍멍이이(가) 공을 가져옵니다
print(cat.info()) # 나비은(는) 고양이입니다
print(cat.make_sound()) # 야옹!
print(cat.climb_tree()) # 나비이(가) 나무에 올라갑니다
다중 상속
class Flyable:
def fly(self):
return "날고 있습니다"
class Swimmable:
def swim(self):
return "수영하고 있습니다"
class Duck(Animal, Flyable, Swimmable):
def __init__(self, name):
super().__init__(name, "오리")
def make_sound(self):
return "꽥꽥!"
# 사용 예시
duck = Duck("도날드")
print(duck.info()) # 도날드은(는) 오리입니다
print(duck.make_sound()) # 꽥꽥!
print(duck.fly()) # 날고 있습니다
print(duck.swim()) # 수영하고 있습니다
특수 메서드 (Magic Methods)
class Book:
def __init__(self, title, author, pages):
self.title = title
self.author = author
self.pages = pages
# 문자열 표현
def __str__(self):
return f"'{self.title}' by {self.author}"
def __repr__(self):
return f"Book('{self.title}', '{self.author}', {self.pages})"
# 길이
def __len__(self):
return self.pages
# 비교 연산자
def __eq__(self, other):
return self.pages == other.pages
def __lt__(self, other):
return self.pages < other.pages
# 덧셈 연산자
def __add__(self, other):
total_pages = self.pages + other.pages
return f"합쳐진 책 ({total_pages} 페이지)"
# 사용 예시
book1 = Book("Python Guide", "Alice", 300)
book2 = Book("Data Science", "Bob", 250)
print(str(book1)) # 'Python Guide' by Alice
print(repr(book1)) # Book('Python Guide', 'Alice', 300)
print(len(book1)) # 300
print(book1 == book2) # False
print(book1 > book2) # True
print(book1 + book2) # 합쳐진 책 (550 페이지)
프로퍼티 (Property)
class Circle:
def __init__(self, radius):
self._radius = radius # 보호된 변수 (관례)
@property
def radius(self):
return self._radius
@radius.setter
def radius(self, value):
if value < 0:
raise ValueError("반지름은 음수가 될 수 없습니다")
self._radius = value
@property
def area(self):
return 3.14159 * self._radius ** 2
@property
def circumference(self):
return 2 * 3.14159 * self._radius
# 사용 예시
circle = Circle(5)
print(circle.radius) # 5
print(circle.area) # 78.53975
print(circle.circumference) # 31.4159
circle.radius = 3
print(circle.area) # 28.27431
# circle.radius = -1 # ValueError 발생
예외 처리
기본 예외 처리
# try-except 기본 구조
try:
number = int(input("숫자를 입력하세요: "))
result = 10 / number
print(f"결과: {result}")
except ValueError:
print("잘못된 숫자 형식입니다")
except ZeroDivisionError:
print("0으로 나눌 수 없습니다")
except Exception as e:
print(f"예상치 못한 오류: {e}")
다양한 예외 처리 패턴
# 여러 예외를 한 번에 처리
try:
# 위험한 코드
pass
except (ValueError, TypeError) as e:
print(f"값 또는 타입 오류: {e}")
# else와 finally
try:
file = open("data.txt", "r")
data = file.read()
except FileNotFoundError:
print("파일을 찾을 수 없습니다")
else:
print("파일을 성공적으로 읽었습니다")
print(f"데이터 길이: {len(data)}")
finally:
print("정리 작업을 수행합니다")
if 'file' in locals():
file.close()
사용자 정의 예외
class CustomError(Exception):
"""사용자 정의 예외"""
pass
class AgeError(Exception):
"""나이 관련 오류"""
def __init__(self, age, message="나이가 유효하지 않습니다"):
self.age = age
self.message = message
super().__init__(self.message)
def check_age(age):
if age < 0:
raise AgeError(age, "나이는 음수가 될 수 없습니다")
elif age > 150:
raise AgeError(age, "나이가 너무 많습니다")
else:
print(f"유효한 나이: {age}")
# 사용 예시
try:
check_age(-5)
except AgeError as e:
print(f"오류: {e.message}, 입력된 나이: {e.age}")
예외 발생시키기
def divide(a, b):
if b == 0:
raise ValueError("두 번째 인수는 0이 될 수 없습니다")
return a / b
# assert 문 사용
def factorial(n):
assert n >= 0, "n은 0 이상이어야 합니다"
assert isinstance(n, int), "n은 정수여야 합니다"
if n <= 1:
return 1
return n * factorial(n - 1)
파일 입출력
기본 파일 읽기/쓰기
# 파일 쓰기
with open("example.txt", "w", encoding="utf-8") as file:
file.write("안녕하세요, Python!\n")
file.write("파일 입출력 연습입니다.\n")
# 파일 읽기
with open("example.txt", "r", encoding="utf-8") as file:
content = file.read()
print(content)
# 줄 단위로 읽기
with open("example.txt", "r", encoding="utf-8") as file:
lines = file.readlines()
for i, line in enumerate(lines, 1):
print(f"줄 {i}: {line.strip()}")
# 한 줄씩 처리 (메모리 효율적)
with open("example.txt", "r", encoding="utf-8") as file:
for line in file:
print(line.strip())
다양한 파일 모드
# 파일 모드
# "r" - 읽기 (기본값)
# "w" - 쓰기 (기존 내용 삭제)
# "a" - 추가 (파일 끝에 추가)
# "x" - 배타적 생성 (파일이 이미 존재하면 실패)
# "b" - 바이너리 모드
# "t" - 텍스트 모드 (기본값)
# 추가 모드
with open("log.txt", "a", encoding="utf-8") as file:
file.write("새로운 로그 항목\n")
# 바이너리 파일 처리
with open("image.jpg", "rb") as file:
binary_data = file.read()
print(f"파일 크기: {len(binary_data)} 바이트")
CSV 파일 처리
import csv
# CSV 파일 쓰기
data = [
["이름", "나이", "도시"],
["Alice", 25, "서울"],
["Bob", 30, "부산"],
["Charlie", 35, "대구"]
]
with open("people.csv", "w", newline="", encoding="utf-8") as file:
writer = csv.writer(file)
writer.writerows(data)
# CSV 파일 읽기
with open("people.csv", "r", encoding="utf-8") as file:
reader = csv.reader(file)
for row in reader:
print(row)
# 딕셔너리 형태로 CSV 처리
with open("people.csv", "r", encoding="utf-8") as file:
reader = csv.DictReader(file)
for row in reader:
print(f"이름: {row['이름']}, 나이: {row['나이']}, 도시: {row['도시']}")
JSON 파일 처리
import json
# JSON 데이터
data = {
"name": "Alice",
"age": 30,
"hobbies": ["독서", "영화감상", "등산"],
"address": {
"city": "서울",
"zipcode": "12345"
}
}
# JSON 파일 쓰기
with open("data.json", "w", encoding="utf-8") as file:
json.dump(data, file, ensure_ascii=False, indent=2)
# JSON 파일 읽기
with open("data.json", "r", encoding="utf-8") as file:
loaded_data = json.load(file)
print(loaded_data)
print(f"이름: {loaded_data['name']}")
print(f"취미: {', '.join(loaded_data['hobbies'])}")
정규표현식
기본 정규표현식
import re
# 기본 패턴 매칭
text = "전화번호: 010-1234-5678"
pattern = r"010-\d{4}-\d{4}"
if re.search(pattern, text):
print("전화번호 패턴을 찾았습니다")
# 모든 매치 찾기
text = "이메일: alice@example.com, bob@test.org"
pattern = r"\w+@\w+\.\w+"
emails = re.findall(pattern, text)
print(emails) # ['alice@example.com', 'bob@test.org']
정규표현식 메서드들
import re
text = "Python 3.9.0 was released on 2020-10-05"
# search: 첫 번째 매치
match = re.search(r"\d+\.\d+\.\d+", text)
if match:
print(f"버전: {match.group()}") # 3.9.0
# findall: 모든 매치
numbers = re.findall(r"\d+", text)
print(numbers) # ['3', '9', '0', '2020', '10', '05']
# split: 패턴으로 분할
text = "apple,banana;cherry:grape"
fruits = re.split(r"[,;:]", text)
print(fruits) # ['apple', 'banana', 'cherry', 'grape']
# sub: 치환
text = "전화번호: 010-1234-5678"
masked = re.sub(r"\d{4}-\d{4}", "****-****", text)
print(masked) # 전화번호: 010-****-****
그룹과 캡처
import re
# 그룹 사용
text = "생년월일: 1990-05-15"
pattern = r"(\d{4})-(\d{2})-(\d{2})"
match = re.search(pattern, text)
if match:
print(f"전체: {match.group(0)}") # 1990-05-15
print(f"년도: {match.group(1)}") # 1990
print(f"월: {match.group(2)}") # 05
print(f"일: {match.group(3)}") # 15
# 이름이 있는 그룹
pattern = r"(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})"
match = re.search(pattern, text)
if match:
print(f"년도: {match.group('year')}")
print(f"월: {match.group('month')}")
print(f"일: {match.group('day')}")
유용한 정규표현식 패턴
import re
# 이메일 검증
def validate_email(email):
pattern = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
return bool(re.match(pattern, email))
# 전화번호 추출
def extract_phone_numbers(text):
pattern = r"01[0-9]-\d{3,4}-\d{4}"
return re.findall(pattern, text)
# URL 추출
def extract_urls(text):
pattern = r"https?://[^\s]+"
return re.findall(pattern, text)
# 한글만 추출
def extract_korean(text):
pattern = r"[가-힣]+"
return re.findall(pattern, text)
# 사용 예시
print(validate_email("user@example.com")) # True
print(extract_phone_numbers("연락처: 010-1234-5678, 011-9876-5432"))
print(extract_urls("방문하세요: https://www.python.org"))
print(extract_korean("Hello 안녕하세요 World 세계"))
컴프리헨션
리스트 컴프리헨션
# 기본 리스트 컴프리헨션
numbers = [1, 2, 3, 4, 5]
squares = [x**2 for x in numbers]
print(squares) # [1, 4, 9, 16, 25]
# 조건부 리스트 컴프리헨션
even_squares = [x**2 for x in numbers if x % 2 == 0]
print(even_squares) # [4, 16]
# 중첩 반복문
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flattened = [num for row in matrix for num in row]
print(flattened) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
# 조건부 표현식
numbers = [1, 2, 3, 4, 5]
result = ["짝수" if x % 2 == 0 else "홀수" for x in numbers]
print(result) # ['홀수', '짝수', '홀수', '짝수', '홀수']
딕셔너리 컴프리헨션
# 기본 딕셔너리 컴프리헨션
numbers = [1, 2, 3, 4, 5]
square_dict = {x: x**2 for x in numbers}
print(square_dict) # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
# 조건부 딕셔너리 컴프리헨션
even_squares = {x: x**2 for x in numbers if x % 2 == 0}
print(even_squares) # {2: 4, 4: 16}
# 키-값 변환
original = {"a": 1, "b": 2, "c": 3}
swapped = {v: k for k, v in original.items()}
print(swapped) # {1: 'a', 2: 'b', 3: 'c'}
집합 컴프리헨션
# 집합 컴프리헨션
numbers = [1, 2, 2, 3, 3, 4, 5]
unique_squares = {x**2 for x in numbers}
print(unique_squares) # {1, 4, 9, 16, 25}
# 조건부 집합 컴프리헨션
text = "Hello World"
unique_chars = {char.lower() for char in text if char.isalpha()}
print(unique_chars) # {'h', 'e', 'l', 'o', 'w', 'r', 'd'}
제너레이터 표현식
# 제너레이터 표현식 (메모리 효율적)
numbers = (x**2 for x in range(10))
print(type(numbers)) # <class 'generator'>
# 지연 평가 - 필요할 때만 계산
for square in numbers:
print(square)
# 큰 데이터셋에 유용
sum_of_squares = sum(x**2 for x in range(1000000))
print(sum_of_squares)
제너레이터와 이터레이터
제너레이터 함수
# 기본 제너레이터 함수
def count_up_to(n):
count = 1
while count <= n:
yield count
count += 1
# 사용법
counter = count_up_to(5)
for num in counter:
print(num) # 1, 2, 3, 4, 5
# 제너레이터는 한 번만 사용 가능
counter = count_up_to(3)
print(list(counter)) # [1, 2, 3]
print(list(counter)) # [] (빈 리스트)
피보나치 수열 제너레이터
def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
# 무한 제너레이터 사용
fib = fibonacci()
fibonacci_numbers = []
for _ in range(10):
fibonacci_numbers.append(next(fib))
print(fibonacci_numbers) # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
이터레이터 프로토콜
class CountDown:
def __init__(self, start):
self.start = start
def __iter__(self):
return self
def __next__(self):
if self.start <= 0:
raise StopIteration
self.start -= 1
return self.start + 1
# 사용법
countdown = CountDown(5)
for num in countdown:
print(num) # 5, 4, 3, 2, 1
itertools 모듈
import itertools
# 무한 이터레이터
# count
counter = itertools.count(10, 2) # 10부터 2씩 증가
first_five = [next(counter) for _ in range(5)]
print(first_five) # [10, 12, 14, 16, 18]
# cycle
colors = itertools.cycle(['red', 'green', 'blue'])
color_list = [next(colors) for _ in range(7)]
print(color_list) # ['red', 'green', 'blue', 'red', 'green', 'blue', 'red']
# repeat
repeated = list(itertools.repeat('hello', 3))
print(repeated) # ['hello', 'hello', 'hello']
# 조합 이터레이터
# permutations (순열)
letters = ['A', 'B', 'C']
perms = list(itertools.permutations(letters, 2))
print(perms) # [('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'C'), ('C', 'A'), ('C', 'B')]
# combinations (조합)
combs = list(itertools.combinations(letters, 2))
print(combs) # [('A', 'B'), ('A', 'C'), ('B', 'C')]
# product (데카르트 곱)
colors = ['red', 'blue']
sizes = ['S', 'M', 'L']
products = list(itertools.product(colors, sizes))
print(products) # [('red', 'S'), ('red', 'M'), ('red', 'L'), ('blue', 'S'), ('blue', 'M'), ('blue', 'L')]
데코레이터
기본 데코레이터
# 함수 데코레이터
def my_decorator(func):
def wrapper():
print("함수 실행 전")
func()
print("함수 실행 후")
return wrapper
@my_decorator
def say_hello():
print("안녕하세요!")
# 사용
say_hello()
# 출력:
# 함수 실행 전
# 안녕하세요!
# 함수 실행 후
인수가 있는 함수를 위한 데코레이터
import functools
def my_decorator(func):
@functools.wraps(func) # 원본 함수의 메타데이터 보존
def wrapper(*args, **kwargs):
print(f"함수 {func.__name__} 실행 전")
result = func(*args, **kwargs)
print(f"함수 {func.__name__} 실행 후")
return result
return wrapper
@my_decorator
def add(a, b):
"""두 수를 더합니다"""
return a + b
result = add(3, 5)
print(f"결과: {result}")
print(f"함수 이름: {add.__name__}")
print(f"함수 문서: {add.__doc__}")
실용적인 데코레이터 예시
import time
import functools
# 실행 시간 측정 데코레이터
def timer(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"{func.__name__} 실행 시간: {end_time - start_time:.4f}초")
return result
return wrapper
# 재시도 데코레이터
def retry(max_attempts=3):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
for attempt in range(max_attempts):
try:
return func(*args, **kwargs)
except Exception as e:
print(f"시도 {attempt + 1} 실패: {e}")
if attempt == max_attempts - 1:
raise
return None
return wrapper
return decorator
# 로깅 데코레이터
def log_calls(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"함수 {func.__name__} 호출됨")
print(f"인수: args={args}, kwargs={kwargs}")
result = func(*args, **kwargs)
print(f"반환값: {result}")
return result
return wrapper
# 사용 예시
@timer
@log_calls
def calculate_sum(n):
return sum(range(n))
@retry(max_attempts=3)
def unreliable_function():
import random
if random.random() < 0.7:
raise Exception("임의 오류 발생")
return "성공!"
# 테스트
result = calculate_sum(1000000)
# try:
# result = unreliable_function()
# print(result)
# except Exception as e:
# print(f"최종 실패: {e}")
클래스 데코레이터
# 싱글톤 패턴 데코레이터
def singleton(cls):
instances = {}
def get_instance(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return get_instance
@singleton
class Database:
def __init__(self):
print("데이터베이스 연결 생성")
self.connection = "DB 연결"
# 사용
db1 = Database() # 데이터베이스 연결 생성
db2 = Database() # 새로운 연결 생성되지 않음
print(db1 is db2) # True (같은 인스턴스)
마무리
이번 2편에서는 Python의 중급 개념들을 살펴봤습니다:
주요 내용 요약
- 객체지향 프로그래밍 (클래스, 상속, 특수 메서드)
- 예외 처리와 사용자 정의 예외
- 파일 입출력 (텍스트, CSV, JSON)
- 정규표현식을 이용한 패턴 매칭
- 컴프리헨션을 통한 간결한 코드 작성
- 제너레이터와 이터레이터
- 데코레이터를 이용한 코드 확장
다음 편 예고
3편 - 고급편에서는 다음 내용을 다룰 예정입니다:
- 메타클래스와 동적 클래스 생성
- 컨텍스트 매니저
- 멀티스레딩과 멀티프로세싱
- 비동기 프로그래밍 (async/await)
- 패키지 생성과 배포
- 성능 최적화 기법
연습 과제
- 도서 관리 시스템 (클래스, 상속, 예외 처리)
- 로그 파일 분석기 (파일 입출력, 정규표현식)
- 데이터 처리 파이프라인 (제너레이터, 데코레이터)
Python의 중급 기능들을 마스터하여 더욱 강력한 프로그램을 만들어보세요!
'Language' 카테고리의 다른 글
| Poetry 완전 가이드: 파이썬 프로젝트 관리의 혁신 (0) | 2025.08.14 |
|---|---|
| Python 완전 정복 가이드 - 3편: 고급편 (3) | 2025.08.04 |
| Python 완전 정복 가이드 - 1편: 기초편 (3) | 2025.08.04 |