카테고리 없음

Python 중급자 완벽 가이드 🚀

블로글러 2024. 11. 3. 21:19

파이썬의 심화 개념들을 더 자세히 설명해드릴게요. 각 개념별로 실제 사용 사례와 함께 자세히 알아보겠습니다!

1. 파이썬의 특별한 컬렉션들 📦

리스트(List) 고급 테크닉

numbers = [1, 2, 3, 4, 5]

# 슬라이싱 상세 설명
print(numbers[1:4])    # 인덱스 1부터 3까지
print(numbers[::2])    # 처음부터 끝까지 2칸씩
print(numbers[::-1])   # 역순으로 전체

# 리스트 컴프리헨션 (List Comprehension)
# 기존 방식
squares = []
for x in range(10):
    if x % 2 == 0:
        squares.append(x**2)

# 컴프리헨션 방식 (더 파이썬스러운 방식)
squares = [x**2 for x in range(10) if x % 2 == 0]

딕셔너리(Dictionary) 심화

from collections import defaultdict, Counter

# defaultdict 사용 예시
# 일반 딕셔너리의 경우
normal_dict = {}
words = ['apple', 'banana', 'apple', 'cherry']
for word in words:
    if word not in normal_dict:
        normal_dict[word] = 0
    normal_dict[word] += 1

# defaultdict 사용 시 - 훨씬 간단!
word_count = defaultdict(int)
for word in words:
    word_count[word] += 1  # 키가 없어도 자동으로 0으로 초기화

# Counter 클래스 활용
inventory = Counter(['사과', '바나나', '사과', '오렌지', '바나나', '사과'])
print(inventory['사과'])  # 3 출력
print(inventory.most_common(2))  # [('사과', 3), ('바나나', 2)]

2. 함수형 프로그래밍의 강력함 🎯

데코레이터 상세 설명

def login_required(func):
    """로그인 상태를 체크하는 데코레이터"""
    def wrapper(*args, **kwargs):
        if not is_logged_in():  # 로그인 상태 체크
            raise Exception("로그인이 필요합니다!")
        return func(*args, **kwargs)
    return wrapper

def timer(func):
    """함수 실행 시간을 측정하는 데코레이터"""
    import time
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"{func.__name__} 함수 실행 시간: {end - start:.2f}초")
        return result
    return wrapper

# 데코레이터 사용 예시
@login_required
@timer
def get_user_data(user_id):
    # 데이터베이스에서 사용자 정보를 가져오는 무거운 작업
    return {"id": user_id, "name": "홍길동"}

map, filter, reduce 상세 활용

from functools import reduce

numbers = [1, 2, 3, 4, 5]

# map: 모든 요소에 함수 적용
def double(x):
    return x * 2
doubled = list(map(double, numbers))  # [2, 4, 6, 8, 10]

# filter: 조건에 맞는 요소만 필터링
def is_even(x):
    return x % 2 == 0
evens = list(filter(is_even, numbers))  # [2, 4]

# reduce: 요소들을 하나로 줄이기
def add(x, y):
    return x + y
total = reduce(add, numbers)  # 15 (1+2+3+4+5)

# 람다로 더 간단하게!
doubled = list(map(lambda x: x * 2, numbers))
evens = list(filter(lambda x: x % 2 == 0, numbers))
total = reduce(lambda x, y: x + y, numbers)

3. 객체지향 프로그래밍 심화 🏗️

클래스 메서드와 스태틱 메서드

class Date:
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day

    @classmethod
    def from_string(cls, date_string):
        """문자열로부터 날짜 객체 생성"""
        year, month, day = map(int, date_string.split('-'))
        return cls(year, month, day)

    @staticmethod
    def is_valid_date(date_string):
        """날짜 문자열이 유효한지 검증"""
        try:
            year, month, day = map(int, date_string.split('-'))
            return 1 <= month <= 12 and 1 <= day <= 31
        except:
            return False

# 사용 예시
date1 = Date(2024, 3, 14)               # 일반적인 생성
date2 = Date.from_string('2024-03-14')  # 클래스 메서드로 생성
is_valid = Date.is_valid_date('2024-03-14')  # 정적 메서드 사용

프로퍼티와 접근제어

class BankAccount:
    def __init__(self, initial_balance):
        self._balance = initial_balance  # protected
        self.__transactions = []        # private

    @property
    def balance(self):
        """잔액 조회"""
        return self._balance

    @balance.setter
    def balance(self, amount):
        """잔액 변경"""
        if amount < 0:
            raise ValueError("잔액은 음수가 될 수 없습니다")
        self.__transactions.append(amount - self._balance)
        self._balance = amount

    def get_transaction_history(self):
        """거래 내역 조회"""
        return self.__transactions.copy()  # 복사본 반환

# 사용 예시
account = BankAccount(1000)
print(account.balance)  # 프로퍼티로 접근
account.balance = 2000  # setter 호출

4. 비동기 프로그래밍 실전 ⚡

async/await 상세 예제

import asyncio
import aiohttp
import time

async def fetch_pokemon(session, pokemon_id):
    """포켓몬 정보를 비동기로 가져오기"""
    url = f"https://pokeapi.co/api/v2/pokemon/{pokemon_id}"
    async with session.get(url) as response:
        return await response.json()

async def main():
    async with aiohttp.ClientSession() as session:
        # 여러 포켓몬 정보를 동시에 가져오기
        pokemon_ids = range(1, 11)
        tasks = [fetch_pokemon(session, pid) for pid in pokemon_ids]
        results = await asyncio.gather(*tasks)

        for pokemon in results:
            print(f"포켓몬: {pokemon['name']}")

# 실행 시간 측정
start = time.time()
asyncio.run(main())
end = time.time()
print(f"실행 시간: {end - start:.2f}초")

5. 고급 에러 처리와 디버깅 🔍

커스텀 예외 체인

class ValidationError(Exception):
    """데이터 검증 실패 시 발생하는 예외"""
    pass

class DatabaseError(Exception):
    """데이터베이스 작업 실패 시 발생하는 예외"""
    pass

def save_user_data(user_dict):
    try:
        # 데이터 검증
        if 'name' not in user_dict:
            raise ValidationError("이름은 필수입니다")

        # 데이터베이스 저장 시도
        try:
            save_to_database(user_dict)
        except Exception as e:
            raise DatabaseError("데이터 저장 실패") from e

    except (ValidationError, DatabaseError) as e:
        print(f"에러 발생: {e}")
        print(f"원인: {e.__cause__}")  # 원인 예외 출력

6. 실전 프로젝트: 데이터 분석 파이프라인 💪

import pandas as pd
import numpy as np
from typing import Optional, Dict, List

class DataAnalyzer:
    """데이터 분석을 위한 파이프라인 클래스"""

    def __init__(self, data: pd.DataFrame):
        self.data = data
        self.original_data = data.copy()  # 원본 데이터 보관

    def clean_data(self) -> 'DataAnalyzer':
        """데이터 클렌징"""
        # 결측치 처리
        self.data = self.data.fillna(self.data.mean())
        # 이상치 제거 (IQR 방식)
        Q1 = self.data.quantile(0.25)
        Q3 = self.data.quantile(0.75)
        IQR = Q3 - Q1
        self.data = self.data[~((self.data < (Q1 - 1.5 * IQR)) | 
                               (self.data > (Q3 + 1.5 * IQR)))]
        return self

    def analyze(self) -> Dict:
        """기본 통계 분석 수행"""
        return {
            'basic_stats': self.data.describe(),
            'correlations': self.data.corr(),
            'missing_ratio': self.data.isnull().sum() / len(self.data)
        }

    @timer  # 위에서 정의한 타이머 데코레이터 사용
    def generate_report(self) -> Dict:
        """분석 리포트 생성"""
        return {
            'summary': self.analyze(),
            'data_shape': self.data.shape,
            'data_types': self.data.dtypes.to_dict()
        }

# 사용 예시
data = pd.read_csv('sample_data.csv')
analyzer = DataAnalyzer(data)
report = (analyzer
          .clean_data()
          .generate_report())

성능 최적화 상세 팁 ⚡

1. 제너레이터 활용

def read_large_file(file_path: str, chunk_size: int = 1024):
    """대용량 파일을 조금씩 읽는 제너레이터"""
    with open(file_path, 'r') as file:
        while True:
            data = file.read(chunk_size)
            if not data:
                break
            yield data

# 메모리 효율적인 파일 처리
for chunk in read_large_file('big_file.txt'):
    process_data(chunk)

2. NumPy 최적화

import numpy as np

# 리스트 연산 vs NumPy 연산 비교
def list_operation():
    lst = list(range(1000000))
    return [x ** 2 for x in lst]

def numpy_operation():
    arr = np.arange(1000000)
    return arr ** 2

# 성능 비교
import time

start = time.time()
list_result = list_operation()
print(f"리스트 연산 시간: {time.time() - start:.2f}초")

start = time.time()
numpy_result = numpy_operation()
print(f"NumPy 연산 시간: {time.time() - start:.2f}초")

마치며 🎁

이러한 고급 기능들을 마스터하면 더 효율적이고 견고한 코드를 작성할 수 있습니다. 특히 실전에서는 이런 기능들을 조합해서 사용하는 경우가 많답니다!

  • 데이터 처리할 때는 NumPy와 Pandas를
  • 웹 개발할 때는 비동기 프로그래밍을
  • 큰 프로젝트에서는 객체지향 패턴을
  • 유틸리티 개발할 때는 함수형 프로그래밍을

상황에 맞게 적절히 활용해보세요! 😊


더 깊이 있는 내용이나 특정 주제에 대해 궁금하신 점이 있다면 댓글로 남겨주세요!

728x90