[Python] 파이썬 기초 완전 정리 2단계

파이썬 완벽 가이드: 3단계로 마스터하기
파이썬은 배우기 쉽고 강력하며 다양한 분야에서 활용되는 인기 있는 프로그래밍 언어입니다. 이 가이드에서는 파이썬의 핵심 개념들을 3단계로 나누어 자세하고 상세하게 설명하여, 프로그래밍 초보자부터 숙련된 개발자까지 모두에게 유익한 정보를 제공하고자 합니다.
2단계: 파이썬 심화 및 객체 지향 프로그래밍 (Advanced & OOP)
1단계에서 파이썬의 기본적인 문법과 흐름 제어를 익혔다면, 이제는 더 복잡한 프로그램을 만들고 코드의 재사용성을 높이는 방법을 배울 차례입니다. 이 단계에서는 파이썬의 심화 문법, 객체 지향 프로그래밍(OOP), 예외 처리, 파일 입출력 등 실질적인 애플리케이션 개발에 필수적인 개념들을 다룹니다.
2.1. 함수 심화
1단계에서 기본적인 함수 사용법을 배웠다면, 이번에는 함수의 다양한 활용법과 고급 기능에 대해 알아봅니다.
가변 인자 (*args, **kwargs)
함수를 호출할 때 인자의 개수가 가변적일 경우 유용하게 사용할 수 있습니다.
*args
: Positional Arguments를 튜플 형태로 받습니다.**kwargs
: Keyword Arguments를 딕셔너리 형태로 받습니다.
def print_args(*args):
"""위치 인자들을 튜플로 받아 출력합니다."""
print(f"위치 인자들: {args}")
print_args(1, 2, 3, "hello") # (1, 2, 3, 'hello')
def print_kwargs(**kwargs):
"""키워드 인자들을 딕셔너리로 받아 출력합니다."""
print(f"키워드 인자들: {kwargs}")
print_kwargs(name="Alice", age=30, city="Seoul") # {'name': 'Alice', 'age': 30, 'city': 'Seoul'}
def mix_args(a, b, *args, **kwargs):
"""위치 인자와 키워드 인자를 혼합하여 받습니다."""
print(f"필수 인자: {a}, {b}")
print(f"추가 위치 인자: {args}")
print(f"추가 키워드 인자: {kwargs}")
mix_args(1, 2, 3, 4, name="Bob", job="Developer")
람다 (Lambda) 함수
이름 없는(익명) 함수를 한 줄로 간결하게 정의할 때 사용됩니다. 주로 다른 함수의 인자로 전달될 때 유용합니다.
# 일반 함수
def add(x, y):
return x + y
print(add(1, 2)) # 3
# 람다 함수
add_lambda = lambda x, y: x + y
print(add_lambda(1, 2)) # 3
# filter() 함수와 함께 사용
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(f"짝수만 필터링: {even_numbers}") # [2, 4, 6, 8, 10]
# map() 함수와 함께 사용
squared_numbers = list(map(lambda x: x * x, numbers))
print(f"제곱 값: {squared_numbers}") # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
클로저 (Closure)와 데코레이터 (Decorator) (선택)
함수 심화의 고급 개념으로, 다른 함수를 반환하거나 함수의 동작을 변경할 때 사용됩니다.
- 클로저: 함수가 그 함수가 정의될 때의 환경(자유 변수)을 기억하여, 함수가 실행될 때 그 환경에 접근할 수 있도록 하는 기능입니다.
- 데코레이터: 기존 함수의 코드를 수정하지 않고 함수의 기능을 확장하거나 변경할 때 사용되는 파이썬의 특별한 문법입니다. 주로 로깅, 성능 측정, 인증 등에 활용됩니다.
# 클로저 예시
def outer_function(text):
def inner_function():
print(text) # outer_function의 text 변수에 접근
return inner_function
my_closure = outer_function("안녕하세요!")
my_closure() # "안녕하세요!" 출력
# 데코레이터 예시 (간단한 로깅 데코레이터)
def logger(func):
def wrapper(*args, **kwargs):
print(f"--- {func.__name__} 함수 시작 ---")
result = func(*args, **kwargs)
print(f"--- {func.__name__} 함수 종료 ---")
return result
return wrapper
@logger
def add(a, b):
return a + b
@logger
def multiply(a, b):
return a * b
print(add(10, 20))
print(multiply(5, 6))
2.2. 객체 지향 프로그래밍 (Object-Oriented Programming, OOP)
OOP는 프로그램을 객체들의 상호작용으로 모델링하는 프로그래밍 패러다임입니다. 파이썬은 강력한 객체 지향 기능을 제공하여 코드의 재사용성, 확장성, 유지보수성을 높입니다.
클래스 (Class)와 객체 (Object)
- 클래스: 객체를 생성하기 위한 "설계도" 또는 "틀"입니다. 속성(데이터)과 메서드(함수)를 정의합니다.
- 객체 (인스턴스): 클래스를 기반으로 생성된 실제 "실체"입니다. 클래스의 속성과 메서드를 가집니다.
# 클래스 정의
class Dog:
# 클래스 변수: 모든 인스턴스가 공유하는 속성
species = "Canis familiaris"
# 생성자: 객체가 생성될 때 호출되는 특별한 메서드
def __init__(self, name, breed, age):
# 인스턴스 변수: 각 객체마다 고유한 속성
self.name = name
self.breed = breed
self.age = age
# 인스턴스 메서드: 객체가 수행할 수 있는 동작
def bark(self):
return f"{self.name}가 멍멍 짖습니다!"
def get_age_in_human_years(self):
return self.age * 7
# 객체 (인스턴스) 생성
my_dog = Dog("바둑이", "진돗개", 3)
your_dog = Dog("초코", "푸들", 1)
# 객체의 속성 접근
print(f"내 강아지 이름: {my_dog.name}, 종: {my_dog.species}")
print(f"네 강아지 이름: {your_dog.name}, 종: {your_dog.species}")
# 객체의 메서드 호출
print(my_dog.bark())
print(f"{your_dog.name}는 사람 나이로 {your_dog.get_age_in_human_years()}살 입니다.")
상속 (Inheritance)
기존 클래스(부모 클래스)의 속성과 메서드를 물려받아 새로운 클래스(자식 클래스)를 만드는 기능입니다. 코드의 재사용성을 높이고 계층 구조를 형성하는 데 사용됩니다.
class Animal: # 부모 클래스
def __init__(self, name):
self.name = name
def speak(self):
raise NotImplementedError("하위 클래스에서 이 메서드를 구현해야 합니다.")
class Dog(Animal): # Animal 클래스를 상속
def __init__(self, name, breed):
super().__init__(name) # 부모 클래스의 생성자 호출
self.breed = breed
def speak(self): # 메서드 오버라이딩 (재정의)
return f"{self.name}가 멍멍!"
class Cat(Animal): # Animal 클래스를 상속
def __init__(self, name, color):
super().__init__(name)
self.color = color
def speak(self): # 메서드 오버라이딩
return f"{self.name}가 야옹야옹!"
my_dog = Dog("맥스", "골든 리트리버")
my_cat = Cat("나비", "삼색")
print(my_dog.speak())
print(my_cat.speak())
다형성 (Polymorphism)
서로 다른 클래스의 객체들이 동일한 메서드 호출에 대해 각자의 방식으로 응답하는 능력입니다. 상속과 함께 OOP의 핵심 원리 중 하나입니다.
# 위에서 정의한 Animal, Dog, Cat 클래스 활용
animals = [Dog("바비", "시바견"), Cat("미미", "검은색")]
for animal in animals:
print(animal.speak()) # 각 객체의 speak() 메서드가 호출됨 (다형성)
캡슐화 (Encapsulation)
관련된 데이터(속성)와 그 데이터를 조작하는 메서드(함수)를 하나의 단위(클래스)로 묶고, 외부에서의 직접적인 접근을 제한하는 것을 의미합니다. 파이썬에서는 접근 제어자(private
, protected
)가 없지만, 관례적으로 _
(protected)나 __
(private) 접두사를 사용하여 의도를 나타냅니다.
class BankAccount:
def __init__(self, owner, balance=0):
self.owner = owner
self.__balance = balance # __balance: 외부에서 직접 접근을 제한하는 private 속성으로 간주
def deposit(self, amount):
if amount > 0:
self.__balance += amount
print(f"{amount}원이 입금되었습니다. 잔액: {self.__balance}")
else:
print("0원보다 큰 금액을 입금하세요.")
def withdraw(self, amount):
if 0 < amount <= self.__balance:
self.__balance -= amount
print(f"{amount}원이 출금되었습니다. 잔액: {self.__balance}")
else:
print("잔액이 부족하거나 유효하지 않은 금액입니다.")
def get_balance(self): # 잔액을 조회하는 public 메서드
return self.__balance
account = BankAccount("김코딩", 10000)
account.deposit(5000)
account.withdraw(2000)
# print(account.__balance) # 직접 접근 시 오류 (AttributeError)
print(f"현재 잔액: {account.get_balance()}원")
account.withdraw(20000)
2.3. 예외 처리 (Exception Handling)
프로그램 실행 중 발생할 수 있는 오류(예외)를 미리 예측하고 적절하게 처리하여 프로그램이 비정상적으로 종료되는 것을 방지하는 기법입니다.
try
: 예외가 발생할 가능성이 있는 코드를 작성합니다.except
:try
블록에서 특정 예외가 발생했을 때 실행될 코드를 작성합니다.else
:try
블록에서 예외가 발생하지 않았을 때 실행될 코드를 작성합니다.finally
: 예외 발생 여부와 상관없이 항상 실행될 코드를 작성합니다 (자원 해제 등에 유용).
def divide(a, b):
try:
result = a / b
except ZeroDivisionError: # 0으로 나눌 때 발생하는 예외 처리
print("오류: 0으로 나눌 수 없습니다.")
return None
except TypeError: # 잘못된 타입의 인자를 받을 때 발생하는 예외 처리
print("오류: 숫자만 입력해주세요.")
return None
except Exception as e: # 그 외 모든 예외를 처리
print(f"알 수 없는 오류 발생: {e}")
return None
else:
print("나눗셈 성공!")
return result
finally:
print("나눗셈 함수 실행 종료.")
print(divide(10, 2))
print(divide(10, 0))
print(divide(10, "a"))
print(divide("b", 2)) # TypeError가 먼저 잡힘
except Exception
사용은 피하고, 가능한 한 구체적인 예외 타입을 지정하는 것이 좋습니다.2.4. 파일 입출력 (File I/O)
컴퓨터의 파일 시스템과 상호작용하여 데이터를 읽거나 쓰는 방법을 배웁니다. 데이터를 영구적으로 저장하고 관리하는 데 필수적인 기능입니다.
open()
함수: 파일을 열고 파일 객체를 반환합니다.- 모드:
'r'
(읽기),'w'
(쓰기, 파일이 없으면 생성, 있으면 덮어씀),'a'
(추가 쓰기, 파일 끝에 추가),'x'
(배타적 생성, 파일이 있으면 오류),'b'
(바이너리 모드),'t'
(텍스트 모드, 기본값)
- 모드:
with open(...) as f:
: 파일을 열 때 권장되는 방식입니다. 파일 사용이 끝난 후 자동으로 파일을 닫아주므로 편리하고 안전합니다.
# 텍스트 파일 쓰기 (wt 모드 - write text)
try:
with open("my_file.txt", "w", encoding="utf-8") as f:
f.write("안녕하세요, 파이썬 파일 입출력 예제입니다.\n")
f.write("두 번째 줄입니다.\n")
print("my_file.txt 파일에 쓰기 완료.")
except IOError as e:
print(f"파일 쓰기 오류: {e}")
# 텍스트 파일 읽기 (rt 모드 - read text)
try:
with open("my_file.txt", "r", encoding="utf-8") as f:
content = f.read() # 파일 전체 내용 읽기
print("\n--- my_file.txt 내용 (전체 읽기) ---")
print(content)
except FileNotFoundError:
print("오류: my_file.txt 파일을 찾을 수 없습니다.")
except IOError as e:
print(f"파일 읽기 오류: {e}")
# 라인별로 읽기
try:
with open("my_file.txt", "r", encoding="utf-8") as f:
print("\n--- my_file.txt 내용 (라인별 읽기) ---")
for line in f:
print(line.strip()) # strip()으로 줄바꿈 문자 제거
except FileNotFoundError:
print("오류: my_file.txt 파일을 찾을 수 없습니다.")
# 텍스트 파일에 내용 추가 (at 모드 - append text)
try:
with open("my_file.txt", "a", encoding="utf-8") as f:
f.write("이것은 추가된 내용입니다.\n")
print("\nmy_file.txt 파일에 내용 추가 완료.")
except IOError as e:
print(f"파일 추가 쓰기 오류: {e}")
# 추가된 내용 확인
try:
with open("my_file.txt", "r", encoding="utf-8") as f:
print("\n--- my_file.txt 내용 (추가 후) ---")
print(f.read())
except FileNotFoundError:
print("오류: my_file.txt 파일을 찾을 수 없습니다.")
encoding="utf-8"
을 명시하는 것이 좋습니다. 한글 깨짐 현상을 방지할 수 있습니다.2.5. 고급 자료구조 (Collections 모듈) (선택)
파이썬의 collections
모듈은 내장 자료구조(리스트, 딕셔너리 등)를 확장하거나 특정 목적에 더 적합한 자료구조를 제공합니다.
collections.Counter
: 해시 가능한 객체들의 개수를 세는 데 사용됩니다. 딕셔너리 서브클래스입니다.collections.deque
: 양쪽 끝에서 빠른 추가/삭제가 가능한 덱(Double-ended queue)입니다. 큐나 스택으로 활용하기 좋습니다.collections.defaultdict
: 존재하지 않는 키에 접근할 때 기본값을 자동으로 생성해주는 딕셔너리입니다.
from collections import Counter, deque, defaultdict
# Counter 예시
data = ["apple", "banana", "apple", "cherry", "banana", "apple"]
word_counts = Counter(data)
print(f"단어 개수: {word_counts}") # Counter({'apple': 3, 'banana': 2, 'cherry': 1})
print(f"가장 흔한 단어: {word_counts.most_common(1)}") # [('apple', 3)]
# deque 예시
q = deque()
q.append("A") # 오른쪽 끝에 추가
q.append("B")
q.appendleft("C") # 왼쪽 끝에 추가
print(f"덱: {q}") # deque(['C', 'A', 'B'])
print(f"오른쪽에서 제거: {q.pop()}") # B
print(f"왼쪽에서 제거: {q.popleft()}") # C
print(f"현재 덱: {q}") # deque(['A'])
# defaultdict 예시
# 일반 딕셔너리는 없는 키 접근 시 KeyError 발생
# my_dict = {}
# my_dict['key'] += 1 # 오류
# defaultdict 사용
s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
dd = defaultdict(list) # 리스트를 기본값으로 설정
for k, v in s:
dd[k].append(v)
print(f"그룹화된 딕셔너리: {dd}") # defaultdict(<class 'list'>, {'yellow': [1, 3], 'blue': [2, 4], 'red': [1]})
word_freq = defaultdict(int) # int (0)를 기본값으로 설정
text = "hello world hello python"
for word in text.split():
word_freq[word] += 1
print(f"단어 빈도수: {word_freq}") # defaultdict(<class 'int'>, {'hello': 2, 'world': 1, 'python': 1})
2.6. 제너레이터 (Generators)와 이터레이터 (Iterators) (선택)
대규모 데이터 처리나 메모리 효율적인 코드 작성에 필수적인 개념입니다.
- 이터레이터:
__iter__()
와__next__()
메서드를 구현하여next()
함수로 요소들을 하나씩 순회할 수 있는 객체입니다.for
루프는 내부적으로 이터레이터를 사용합니다. - 제너레이터: 이터레이터를 쉽게 만들 수 있는 특별한 종류의 함수입니다.
yield
키워드를 사용하여 값을 반환하며, 함수 상태를 기억하고 다음 호출 시점에서 이어서 실행됩니다. 모든 요소를 한꺼번에 메모리에 올리지 않고 필요할 때마다 생성하므로 메모리 효율적입니다.
# 이터레이터 예시
my_list = [1, 2, 3]
my_iterator = iter(my_list) # 리스트로부터 이터레이터 생성
print(next(my_iterator)) # 1
print(next(my_iterator)) # 2
print(next(my_iterator)) # 3
# print(next(my_iterator)) # 더 이상 요소가 없으면 StopIteration 예외 발생
# 제너레이터 함수 예시
def fibonacci_sequence(n):
a, b = 0, 1
count = 0
while count < n:
yield a # 값을 반환하고, 상태를 저장
a, b = b, a + b
count += 1
fib = fibonacci_sequence(5)
print(f"피보나치 수열 (제너레이터): {list(fib)}") # [0, 1, 1, 2, 3]
# 제너레이터 표현식 (Generator Expression)
squares = (x*x for x in range(5))
print(f"제곱 제너레이터: {squares}") # at ...>
print(f"제곱 값: {list(squares)}") # [0, 1, 4, 9, 16]
2.7. 가상 환경 (Virtual Environment)
각 프로젝트마다 독립적인 파이썬 개발 환경을 구축하는 방법입니다. 프로젝트 간의 패키지 충돌을 방지하고 의존성을 관리하는 데 필수적입니다.
- 주요 도구:
venv
(파이썬 3.3+ 내장),conda
(Anaconda 배포판 사용 시) - 생성:
python -m venv [환경이름]
(예:python -m venv myenv
) - 활성화:
- Windows:
.\myenv\Scripts\activate
- macOS/Linux:
source myenv/bin/activate
- Windows:
- 비활성화:
deactivate
- 패키지 설치: 가상 환경 활성화 후
pip install [패키지명]
- 설치된 패키지 목록 저장:
pip freeze > requirements.txt
(프로젝트 공유 시 유용) - 패키지 일괄 설치:
pip install -r requirements.txt
# 가상 환경 생성 (프로젝트 폴더 내에서 실행)
python -m venv myproject_env
# 가상 환경 활성화 (Windows)
.\myproject_env\Scripts\activate
# 가상 환경 활성화 (macOS/Linux)
source myproject_env/bin/activate
# (가상 환경 활성화 후) 필요한 패키지 설치
pip install requests beautifulsoup4
# 설치된 패키지 목록 파일로 저장
pip freeze > requirements.txt
# (다른 환경에서) 필요한 패키지 일괄 설치
pip install -r requirements.txt
# 가상 환경 비활성화
deactivate