반응형

파이썬 매직 메서드(Magic Method) 완전 정복 🧙‍♂️

여러분,
__init__, __str__, __add__ 같은 이상한 이름의 메서드들,
한 번쯤 보셨죠?
이거 그냥 넘어가면 진짜 손해예요!

 

 

안녕하세요!

이번 글에서는 파이썬 객체지향 프로그래밍에서 빼놓을 수 없는 매직 메서드에 대해 알아보려고 해요.

이름부터 범상치 않죠?

마법 같아 보이는 이 메서드들은 사실 객체의 동작을 정의해주는 파이썬의 핵심 기능이에요.

예를 들어

우리가 print(객체)를 했을 때 예쁘게 출력되거나, 객체1 + 객체2가 가능해지는 것도 모두 매직 메서드 덕분이랍니다.

이 글에서는 기초부터 실전 활용까지 하나하나 친절하게 알려드릴게요.

특히 개발 초보자분들이 이해하기 쉽도록 예제 위주로 설명드리니, 걱정하지 마시고 끝까지 함께 해요!

1. __init__ 생성자의 진짜 역할 🛠

__init__ 메서드는 클래스의 객체가 만들어질 때 자동으로 호출되는 생성자 메서드예요.

객체를 초기화할 때 사용되며, 인스턴스를 만들자마자 실행되죠.

마치 입학식에서 이름표를 붙여주는 느낌이랄까요?

기본 구조와 사용법

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

p1 = Person("철수", 30)
print(p1.name)  # 철수
print(p1.age)   # 30

객체 p1을 만들자마자 __init__이 실행돼서 self.nameself.age에 값을 할당한 거예요.

이게 없으면 객체가 '텅 빈 상태'로 만들어지겠죠!

왜 꼭 필요할까요?

  • 객체 생성과 동시에 필요한 데이터를 초기화할 수 있어요.
  • 오류 방지에도 효과적이에요. 값이 없는 상태에서 메서드를 호출하면 AttributeError가 발생할 수 있거든요.
  • 프로그램의 구조와 흐름을 명확하게 만들 수 있어요.

Tip! 꼭 기억하세요

__init__의 첫 번째 매개변수는 반드시 self여야 해요.

이건 객체 자신을 가리키는 약속된 이름이거든요.

다른 이름으로 바꿔도 되긴 하지만... 안 쓰는 게 좋아요.

혼란만 생기니까요 😅

정리해볼까요?

항목 내용
정의 객체 생성 시 자동 호출되는 초기화 메서드
문법 def __init__(self, ...):
역할 객체에 필요한 데이터를 초기 세팅
주의사항 self는 꼭 첫 번째 인자로 지정

 

2. __str__로 객체를 예쁘게 출력하기 💬

__str__ 메서드는 객체를 문자열로 표현할 때 호출되는 매직 메서드예요.

우리가 print(객체)를 했을 때 보이는 결과, 그게 바로 __str__ 덕분이죠.

이 메서드를 정의하지 않으면 기본값으로 <__main__.클래스명 object at 0x~~~>처럼 딱딱하고 보기 힘든 문자열이 출력돼요.

예제로 이해하는 __str__

class Book:
    def __init__(self, title, author):
        self.title = title
        self.author = author

    def __str__(self):
        return f"『{self.title}』 by {self.author}"

book1 = Book("파이썬 마스터", "홍길동")
print(book1)

위 코드에서 __str__ 메서드는 책 정보를 예쁘게 문자열로 포장해서 보여주고 있어요.

print(book1)을 하면 “『파이썬 마스터』 by 홍길동”이 출력되죠.

완전 깔끔하죠? 😎

__repr__과의 차이점은?

  • __str__은 사용자 친화적인 설명용, 즉 ‘보기 좋게’ 출력되는 문자열
  • __repr__은 디버깅이나 로그용, ‘개발자용’ 정보 중심 출력

예를 들어 리스트를 출력할 때 내부 객체에 __str__이 없으면 __repr__이 호출돼요.

실제 개발에서는 __str____repr__을 모두 정의해두는 게 좋아요.

보너스 팁 💡

__str__ 안에서는 꼭 문자열을 반환해야 해요!

print()를 해도 None이 뜬다면 return이 빠졌는지 확인해보세요.

정리 요약 📌

항목 내용
정의 print(객체) 또는 str(객체) 호출 시 실행되는 메서드
역할 객체의 정보를 보기 좋게 문자열로 반환
반드시 반환? 문자열을 return해야 정상 작동
__repr__과 차이 __repr__은 개발자용, __str__은 사용자용

 

3. __add__로 객체끼리 덧셈 구현하기 ➕

__add__ 메서드는 우리가 흔히 쓰는 + 연산자를 객체끼리 사용할 수 있게 해주는 매직 메서드예요.

예를 들어,

두 개의 숫자형 객체 또는 좌표 객체를 + 연산으로 결합하고 싶다면 이 메서드를 활용하면 됩니다!

기본 사용 예제

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, other):
        return Point(self.x + other.x, self.y + other.y)

    def __str__(self):
        return f"({self.x}, {self.y})"

p1 = Point(2, 3)
p2 = Point(4, 1)
print(p1 + p2)  # (6, 4)

p1 + p2는 사실 p1.__add__(p2)로 호출돼요.

즉, __add__는 + 기호의 비밀 통로 같은 존재죠. 덕분에 코드가 훨씬 읽기 쉬워집니다.

주의할 점

  • other는 반드시 같은 클래스의 인스턴스라는 보장이 없어요. 타입 체크 필수!
  • 반환 값은 가급적 새로운 인스턴스로 만들어야 해요. 원본을 수정하는 건 좋지 않아요.

타입 확인 예제

def __add__(self, other):
    if not isinstance(other, Point):
        return NotImplemented
    return Point(self.x + other.x, self.y + other.y)

NotImplemented를 반환하면 파이썬이 다른 방법으로 연산을 시도하게 돼요.

(예: other.__radd__() 호출)

정리 요약 🔁

항목 내용
정의 객체 간 + 연산 정의
문법 def __add__(self, other):
반환 값 일반적으로 새로운 객체
활용 예 좌표, 벡터, 통계값 등 덧셈이 자연스러운 객체

 

4. __eq__로 객체 비교 가능하게 만들기 🔍

__eq__는 객체끼리 == 연산을 할 수 있도록 만들어주는 매직 메서드예요.

기본적으로 객체는 동일한 인스턴스일 때만 같다고 판단하지만, __eq__를 재정의하면 속성 값 기준으로 비교할 수 있어요.

예를 들어, 두 책 객체의 제목과 저자가 같다면 동일한 책으로 판단할 수 있게 되는 거죠!

기본 사용 예제

class Book:
    def __init__(self, title, author):
        self.title = title
        self.author = author

    def __eq__(self, other):
        return self.title == other.title and self.author == other.author

book1 = Book("파이썬 기초", "홍길동")
book2 = Book("파이썬 기초", "홍길동")
book3 = Book("파이썬 고급", "홍길동")

print(book1 == book2)  # True
print(book1 == book3)  # False

보셨죠? __eq__ 덕분에 == 연산이 단순히 메모리 주소 비교가 아니라 내용 기반 비교로 바뀌었어요.

정말 강력한 기능이에요!

주의할 점 💡

  • 타입 검사는 필수입니다! 다른 클래스와 비교할 경우 오류가 날 수 있어요.
  • __eq__만 정의하면 != 연산자는 자동 지원되지 않아요. __ne__도 같이 정의하면 좋아요.

타입 검사 버전 예시

def __eq__(self, other):
    if not isinstance(other, Book):
        return NotImplemented
    return self.title == other.title and self.author == other.author

정리 요약 📑

항목 내용
정의 == 연산자를 커스터마이징할 수 있는 매직 메서드
활용 속성 기반 비교, 테스트 자동화 시 유용
보완 __ne__ 같이 정의 권장
타입 검사 isinstance 또는 type()으로 비교

 

5. 자주 쓰는 매직 메서드 리스트 🧾

지금까지 배운 __init__, __str__, __add__, __eq__ 외에도 파이썬에는 다양한 매직 메서드(Magic Method)들이 있어요.

이 메서드들을 활용하면 클래스를 파이썬스럽게 쓰는 멋진 코드를 만들 수 있습니다.

여기서는 자주 쓰이는 매직 메서드들을 분야별로 정리해봤어요!

💡 생성 및 초기화 관련

메서드 설명
__new__(cls) 객체 생성 시 가장 먼저 호출됨 (보통 잘 안 씀)
__init__(self) 객체 생성 후 초기화

🖨 출력 및 표현 관련

메서드 설명
__str__ print() 시 출력 형태 지정
__repr__ 개발자용 디버깅 출력 문자열

➕ 연산자 오버로딩 관련

메서드 역할
__add__ +
__sub__ -
__mul__ *
__truediv__ / (나누기)
__mod__ % (나머지)

✅ 비교 관련 메서드

메서드 역할
__eq__ == (같다)
__ne__ != (다르다)
__lt__ < (작다)
__le__ <= (작거나 같다)
__gt__ > (크다)
__ge__ >= (크거나 같다)

 

이 외에도 __len__, __getitem__, __call__ 등 정말 많은 매직 메서드들이 있어요.

하지만 걱정 마세요. 상황에 맞게 하나씩만 잘 써도 충분히 파이썬 고수가 될 수 있어요! 😉

 

 

마무리 🎯

파이썬의 매직 메서드, 처음 보면 좀 낯설고 복잡해 보일 수 있어요.

이름도 특이하고 동작 방식도 조금은 추상적이죠.

그런데 한 번만 제대로 이해하고 나면, 객체지향 프로그래밍이 훨씬 자연스럽고 재밌어져요.

오늘 배운 __init__, __str__, __add__, __eq__부터 시작해서 다양한 연산자 오버로딩 메서드들까지, 실제 실무에서 자주 등장하는 개념들이니 꼭 익혀두시면 좋아요.

혹시 지금도 이해가 100% 안 된다면 괜찮아요.

직접 클래스를 만들어보고 print도 해보고, 덧셈도 해보고 하면서 연습해보세요.

그게 가장 빠른 학습법이랍니다! 😊

반응형
반응형

파이썬 클래스(Class)로 배우는 객체지향 프로그래밍

객체지향 프로그래밍 어렵다고 느끼셨나요?
파이썬 클래스 한 번 이해하면 생각보다 엄청 쉬워요!

 

 

안녕하세요, 여러분 😊

오늘은 파이썬의 꽃이라고도 할 수 있는 클래스(Class)객체지향 프로그래밍(OOP)에 대해 이야기해볼까 해요.

처음 접하면 '뭐가 이렇게 복잡해?' 싶지만, 실제로는 우리가 일상에서 자주 쓰는 '설계도와 실물 제품'의 관계랑 비슷해서 이해하기 쉽답니다.

이 글에서는 클래스의 기본 구조부터 메서드와 생성자, 그리고 상속오버라이딩까지, 꼭 알아야 할 핵심 개념들을 차근차근 예제와 함께 알려드릴게요.

끝까지 함께 해주시면, 여러분도 객체지향 프로그래밍이 어렵지 않다는 걸 느끼실 수 있을 거예요! 🚀

1. 클래스와 객체란? 🧱

클래스(Class)객체(Object)는 파이썬에서 객체지향 프로그래밍의 핵심 개념이에요.

이 두 가지를 이해하면 코드의 재사용성과 확장성을 높일 수 있어요.

쉽게 말해, 클래스는 설계도이고 객체는 그 설계도로 만들어진 제품이에요.

클래스와 객체의 관계

  • 클래스(Class): 반복해서 만들 수 있는 설계도
  • 객체(Object): 클래스를 통해 만들어진 실체

예를 들어,

'자동차'라는 클래스를 만들면, 이 클래스를 바탕으로 만든 여러 대의 자동차들이 객체가 되는 거죠.

각 객체는 서로 다른 속성(색상, 속도 등)을 가질 수 있고, 독립적으로 존재할 수 있어요.

기초 예제: Cookie 클래스


class Cookie:
    pass

a = Cookie()
b = Cookie()

위 예제는 아주 기본적인 클래스 정의예요.

pass는 아직 클래스 안에 아무 기능도 넣지 않았다는 뜻이에요.

그럼에도 불구하고 a, b라는 객체를 만들 수 있어요! 🤖

이처럼 클래스는 객체를 만들어낼 수 있는 ‘틀’인 셈이죠.

객체의 특징 🧩

  • 클래스에서 만든 객체는 고유한 성격을 가질 수 있음
  • 동일한 클래스라도 객체들끼리는 서로 영향 없음 (독립적!)

비유로 이해해 볼까요? ☕

카페에서 같은 메뉴의 커피를 여러 잔 주문한다고 상상해보세요.

메뉴판이 클래스라면, 주문해서 나온 커피 한 잔 한 잔이 객체예요.

커피는 메뉴는 같지만, 누군가는 시럽을 추가할 수도 있고, 누군가는 휘핑을 빼달라고 할 수도 있죠.

이렇게 객체는 각자 다르게 행동할 수 있어요.

정리 ✍️

항목 설명
클래스 객체를 만들기 위한 설계도
객체 클래스를 통해 만들어진 실체
예시 a = Cookie() → a는 Cookie 클래스의 객체

이제 클래스와 객체의 개념이 좀 감이 오시죠? 😊

다음으로는 객체 내부의 동작을 담당하는 메서드와 self에 대해 자세히 알아볼 거예요!

 

 

2. 메서드와 self 이해하기 🔁

클래스 내부에 정의된 함수는 메서드(method)라고 부릅니다.

메서드는 객체의 동작을 정의하는 도구예요.

이 메서드를 제대로 활용하려면 self라는 키워드의 개념을 먼저 이해해야 해요.

처음 보면 낯설고 헷갈릴 수 있지만, 알고 보면 생각보다 단순하답니다!

self의 정체는?

self는 객체 자기 자신을 가리키는 변수예요. 메서드 안에서 self를 통해 해당 객체의 속성이나 다른 메서드에 접근할 수 있어요.

예를 들어

어떤 객체 aa.setdata(3, 4)를 호출하면, self에는 자동으로 a가 전달됩니다.


class FourCal:
    def setdata(self, first, second):
        self.first = first
        self.second = second

이렇게 self.first = first는 “이 객체의 first라는 속성에 외부에서 받은 값을 넣어줘” 라는 뜻이에요. self가 없으면 객체 각각의 속성을 구분할 수 없겠죠?

self 없이 메서드를 호출하면? 🤔

만약 self를 메서드에 넣지 않으면, 파이썬은 객체가 호출한 메서드임을 인식하지 못하고 에러를 내요.

객체 메서드에는 항상 첫 번째 인자로 self가 있어야 해요.

메서드 사용 예제


a = FourCal()
a.setdata(3, 4)

print(a.first)  # 3
print(a.second) # 4

위처럼 setdata 메서드를 통해 a 객체는 firstsecond라는 두 개의 속성을 가지게 됩니다.

이 속성들은 각각의 객체에 독립적으로 존재해요.

즉, 다른 객체에는 영향을 주지 않아요!

비교 실험: 객체 간 속성 독립성


b = FourCal()
b.setdata(5, 6)

print(a.first)  # 여전히 3
print(b.first)  # 5
객체명 first 값
a 3
b 5

이렇게 같은 클래스에서 만들어졌더라도 각 객체는 서로 완전히 독립적이에요.

self를 통해 객체 각각의 데이터가 보존되고, 서로 영향을 주지 않기 때문에 가능한 일이죠.

이게 바로 객체지향의 “캡슐화(Encapsulation)” 개념이기도 해요!

다음 장에서는 객체가 만들어질 때 자동으로 호출되는 생성자 메서드 __init__()에 대해 배워볼게요.

이제 객체 생성과 초기화의 마법을 직접 경험해봅시다! ✨

 

 

3. 생성자(__init__)의 역할 🔨

파이썬에서는 객체가 생성될 때 자동으로 실행되는 특별한 메서드가 있어요.

그게 바로 __init__(), 일명 생성자(constructor)입니다.

객체를 만들자마자 초기값을 설정할 수 있게 해주는 이 메서드는 클래스 안에서 굉장히 중요한 역할을 해요.

생성자가 필요한 이유

앞에서 만든 FourCal 클래스는 setdata() 메서드로 데이터를 입력받았죠.

그런데 실수로 setdata()를 안 하고 add()를 호출하면 어떻게 될까요?


a = FourCal()
print(a.first)  # AttributeError 발생

바로 AttributeError가 발생합니다.

first 속성이 아직 존재하지 않기 때문이에요.

이런 문제를 방지하려면 객체 생성과 동시에 데이터를 넣는 방법이 필요하고, 그 해답이 바로 __init__()이에요!

생성자 사용 예제


class FourCal:
    def __init__(self, first, second):
        self.first = first
        self.second = second

    def add(self):
        return self.first + self.second

이제 객체를 만들 때 바로 값을 넣을 수 있어요 👇


a = FourCal(3, 5)
print(a.add())  # 8

멋지죠?

이렇게 하면 실수로 setdata()를 호출하지 않아 생기는 오류를 방지할 수 있고, 객체의 초기 상태도 깔끔하게 설정할 수 있어요.

생성자의 매개변수 개수 주의!

생성자를 정의할 때 __init__(self, first, second)처럼 매개변수를 정하면, 객체 생성 시에도 반드시 해당 값을 전달해야 해요.

아래처럼 파라미터 없이 생성하면 에러 발생!


a = FourCal()  # TypeError 발생

생성자와 메서드의 관계

  • 생성자는 객체를 만들 때 한 번 자동 실행됨
  • 일반 메서드는 객체가 만든 이후에 원하는 만큼 호출 가능

정리 🧾

구분 설명
__init__() 객체 생성 시 자동 호출되는 메서드
일반 메서드 필요할 때 직접 호출해야 작동

이제 여러분은 클래스가 객체를 만들 때 어떤 방식으로 초기화를 하는지, 왜 생성자가 중요한지를 이해하셨어요.

 

다음 파트에서는 객체 변수의 독립성에 대해 더 깊이 들여다볼게요. 👀

 

 

4. 객체 변수의 독립성 이해하기 🔍

객체를 여러 개 만들면, 각 객체는 서로 다른 객체 변수(instance variable)를 가질 수 있어요.

이 말은 곧 클래스는 같아도, 객체마다 저장된 값은 서로 독립적이라는 뜻이죠! 😎

이 개념은 객체지향 프로그래밍에서 아주 중요한 원칙이에요.

객체 변수란?

객체가 생성될 때 생성자나 메서드를 통해 self.변수명 형식으로 선언되는 변수예요.

이 변수는 해당 객체에만 속하며, 다른 객체에는 영향을 주지 않아요.


class FourCal:
    def setdata(self, first, second):
        self.first = first
        self.second = second

여러 객체를 생성해보자!


a = FourCal()
b = FourCal()

a.setdata(4, 2)
b.setdata(3, 7)

print(a.first)  # 4
print(b.first)  # 3

이처럼 ab는 같은 클래스에서 만들어졌지만, 각자의 first 값은 다릅니다.

하나를 수정한다고 다른 하나에 영향을 주지 않죠.

실험: 객체 변수 독립성 테스트

객체명 first 값 second 값
a 4 2
b 3 7

이걸 왜 중요하게 생각해야 할까?

  • 각각의 객체는 독립적인 데이터를 관리할 수 있어야 한다.
  • 하나의 객체의 값 변경이 전체 클래스에 영향을 주면 유지보수가 어려워짐.

이 원리를 이해하면 앞으로 클래스와 객체를 활용할 때 의도치 않은 버그를 방지할 수 있어요. 😊

 

다음 단계에서는 객체지향의 꽃이라 할 수 있는 상속(Inheritance)에 대해 배워볼 거예요.

기존 기능을 재사용하고 확장하는 아주 중요한 기능이죠!

 

 

5. 클래스 상속으로 기능 확장하기 🧬

파이썬 클래스의 가장 강력한 기능 중 하나가 바로 상속(Inheritance)이에요.

상속은 말 그대로 기존 클래스를 물려받아 새로운 클래스를 만드는 방법이에요.

기존 클래스의 기능을 그대로 사용할 수 있고, 필요한 기능만 추가하거나 바꾸면 되기 때문에 아주 효율적이죠.

기본 상속 구조 이해하기


class FourCal:
    def __init__(self, first, second):
        self.first = first
        self.second = second

    def add(self):
        return self.first + self.second

class MoreFourCal(FourCal):
    def pow(self):
        return self.first ** self.second

위 코드에서 MoreFourCal 클래스는 FourCal 클래스를 상속받아요.

그래서 FourCaladd() 메서드는 물론, __init__() 생성자까지 그대로 사용할 수 있어요.

거기에 pow()라는 새로운 기능도 추가했죠!

사용 예제


a = MoreFourCal(4, 2)

print(a.add())  # 6
print(a.pow())  # 16

이처럼 상속을 활용하면 기존 코드 재사용 + 기능 확장을 동시에 이룰 수 있어요.

코드를 반복해서 작성할 필요도 없고, 유지보수도 쉬워집니다!

상속의 구조 요약

구성 요소 의미
부모 클래스 기존 기능을 가진 클래스 (예: FourCal)
자식 클래스 부모 클래스를 상속받는 클래스 (예: MoreFourCal)
추가 기능 자식 클래스에만 정의된 새로운 메서드

상속이 실무에서 중요한 이유 🤔

  • 여러 기능을 공통으로 사용해야 하는 클래스 구조에서 코드 중복 제거
  • 새로운 기능 추가가 쉬움 (자식 클래스에서만 추가/변경하면 됨)

자, 여기까지 배우셨다면 객체지향의 핵심 중 하나인 상속에 대해 감 잡으셨을 거예요! 마지막으로, 상속받은 기능 중 일부를 오버라이딩해서 동작을 바꾸는 방법도 함께 배워볼까요?

 

 

6. 메서드 오버라이딩으로 동작 변경하기 🔁

상속을 활용하면 부모 클래스의 기능을 물려받을 수 있죠.

그런데 때로는 부모의 메서드를 그대로 쓰고 싶지 않을 때도 있어요.

예를 들어,

기존 메서드가 너무 위험하거나, 다른 방식으로 동작하길 바랄 때 말이죠.

이럴 땐 메서드 오버라이딩(method overriding)을 사용하면 됩니다!

오버라이딩이란?

부모 클래스에 정의된 메서드를 자식 클래스에서 같은 이름으로 다시 정의하는 것을 오버라이딩이라고 해요.

오버라이딩된 메서드는 부모 클래스의 메서드를 덮어쓰게 되며, 객체는 자식 클래스에 정의된 메서드를 우선 사용합니다.

예제: 나눗셈 안전하게 처리하기


class FourCal:
    def __init__(self, first, second):
        self.first = first
        self.second = second

    def div(self):
        return self.first / self.second

class SafeFourCal(FourCal):
    def div(self):
        if self.second == 0:
            return "0으로 나눌 수 없습니다!"
        return self.first / self.second

이제 SafeFourCal 클래스를 사용하면 0으로 나눌 때 오류가 발생하지 않아요.

div() 메서드를 자식 클래스에서 오버라이딩했기 때문이죠.

아래처럼 사용하면 됩니다:


a = SafeFourCal(4, 0)
print(a.div())  # 출력: 0으로 나눌 수 없습니다!

오버라이딩 요약 포인트

  • 메서드 이름과 매개변수가 같아야 함
  • 부모 클래스의 기능을 ‘내 입맛’에 맞게 바꾸는 데 유용

정리 및 마무리 💡

기능 설명
상속 부모 클래스의 기능을 자식 클래스가 그대로 물려받음
오버라이딩 부모 클래스의 메서드를 자식 클래스에서 재정의

이제 여러분은 파이썬 클래스의 기본 구조부터 객체, 메서드, 생성자, 상속 그리고 오버라이딩까지 모두 익히셨습니다! 👏

 

마지막으로 오늘 배운 내용을 정리하며 실전에서 어떻게 활용할 수 있을지 살펴보고, 블로그 포스트를 마무리해볼게요.

 

 

마무리 🧭

오늘은 파이썬의 객체지향 프로그래밍 핵심인 클래스(Class) 개념을 기초부터 차근차근 알아봤어요.

단순한 구조부터 시작해서 메서드, 생성자, 상속, 오버라이딩까지 다양한 요소들을 배우면서 "클래스가 뭐지?"라는 질문에 명확한 답을 얻을 수 있었길 바랍니다 😊

이제 여러분은 파이썬으로 반복적인 작업을 자동화하고, 유연한 프로그램을 만들 수 있는 구조적 사고를 갖췄다고 할 수 있어요.

그리고 이 클래스 개념은 웹 개발, 게임 제작, 인공지능, 데이터 처리 등 어디서든 활용된답니다!

클래스는 단순히 문법이 아니라, 효율적인 사고방식이에요.

객체 단위로 세상을 바라보는 연습을 계속해 나가면, 분명 더 멋진 프로그램을 만들 수 있을 거예요.

 

다음에는 클래스 기반으로 더 복잡한 구조나 실제 프로젝트에 적용하는 방법을 함께 알아보도록 할게요! ✨

💬 오늘 내용 요약

  • 클래스와 객체는 설계도와 실체의 관계다
  • 메서드는 객체 동작의 정의, self는 자기 자신을 가리킨다
  • __init__ 생성자를 사용하면 객체 초기화를 자동화할 수 있다
  • 객체 변수는 서로 독립적으로 존재한다
  • 상속을 통해 코드 재사용과 기능 확장이 가능하다
  • 오버라이딩으로 부모 메서드의 기능을 재정의할 수 있다

읽어주셔서 감사합니다!

파이썬 클래스에 대해 더 궁금한 점이 있다면 언제든지 댓글로 질문해주세요 💬

 

다음 포스팅에서는 클래스 응용, 모듈화, 또는 간단한 프로젝트 구현 예제도 다뤄볼게요 🚀

반응형
반응형

파이썬의 표준 입출력 완전 정복 📘

당신의 코드는 왜 입력받는 데에 버벅일까요?
혹시 input()이랑 print()만 알고 있다면,
지금이 바로 더 깊이 있게 배워야 할 타이밍입니다!

 

 

안녕하세요, 여러분 😊

파이썬을 배우다 보면 가장 처음 접하는 것 중 하나가 바로 "표준 입출력"이죠.

그런데 단순히 입력을 받는 input() 함수, 출력하는 print() 함수만 알고 계시다면, 아직 파이썬의 진짜 매력을 다 맛본 게 아닙니다.

오늘은 우리가 일상적으로 마주치는 사용자 입출력, 그리고 파일을 읽고 쓰는 다양한 방법까지 낱낱이 파헤쳐 볼 거예요.

특히 입출력에서 발생할 수 있는 오류 처리 방법과 with 문을 활용한 파일 핸들링까지 꼭 필요한 예제 중심으로 소개해드릴게요.

그럼, 같이 출발해볼까요?

1. 사용자 입력 처리하기: input 함수 제대로 쓰기 ✍️

파이썬을 배우면서 가장 먼저 만나는 함수 중 하나가 바로 input()입니다.

우리가 키보드로 입력한 값을 프로그램이 받아들일 수 있게 해주는 함수죠.

그런데 이 단순한 함수, 알고 보면 꽤 많은 기능을 할 수 있다는 거 아셨나요? 😲

input 함수의 기본 구조 🧱

input() 함수는 사용자의 키보드 입력을 받아서 문자열(str) 형태로 반환해줍니다.

아무리 숫자를 입력해도, 파이썬은 그것을 문자로 인식한다는 점!

그래서 입력값을 숫자로 활용하고 싶다면 꼭 int()float() 같은 형 변환이 필요해요.

name = input("당신의 이름은? ")
print("안녕하세요,", name, "님!")

위 코드를 실행하면 콘솔에 "당신의 이름은?"이라는 문구가 먼저 나오고, 사용자가 입력을 하면 그 값을 받아 출력해줍니다.

아주 기본적인 흐름이지만, 이걸 잘 다루면 대화형 프로그램도 얼마든지 만들 수 있어요!

숫자를 입력받을 때 주의할 점 ⚠️

age = input("당신의 나이는? ")
print(age + 1)  # 오류 발생!

위 코드는 실행하면 에러가 납니다. 왜일까요? 🤔

바로 input()은 문자열을 반환하기 때문이죠.

숫자 연산을 하려면 int()로 형을 바꿔줘야 해요.

age = int(input("당신의 나이는? "))
print(age + 1)

이제야 원하는 숫자 연산이 가능해졌네요!

이처럼 입력값이 문자열이라는 사실을 꼭 기억하고, 상황에 맞게 형 변환을 해주는 습관을 들이세요.

여러 값 입력받기: split() 활용 💡

하나의 입력줄에 여러 값을 넣고 싶다면 split() 메서드를 사용하면 돼요.

예를 들어 이름과 나이를 동시에 입력받고 싶을 때 이렇게 쓸 수 있어요:

name, age = input("이름과 나이를 입력하세요 (띄어쓰기로 구분): ").split()
print(name, "님은", age, "살이군요!")

이 방식은 공백으로 구분된 값을 각각 나누어 변수에 저장할 수 있어요.

단, 입력값 개수가 변수 개수와 꼭 맞아야 한다는 점은 주의!

map 함수로 숫자 입력 변환까지 한 번에 처리하기

a, b = map(int, input("두 정수를 입력하세요: ").split())
print("합:", a + b)

이 코드처럼 map()을 사용하면 입력된 문자열을 숫자로 바로 변환할 수 있어요.

간단하면서도 강력한 한 줄짜리 코드죠!

input 함수 사용 시 체크포인트 ✅

  • 모든 입력은 기본적으로 문자열로 처리됨
  • 숫자 처리 시에는 형변환 필수: int(), float()
  • 여러 값 입력은 split()과 map() 조합으로 깔끔하게 처리

이제 input() 함수 하나만으로도 꽤 많은 작업을 할 수 있겠죠?

다음은 print 함수를 활용해 어떻게 출력을 다양하게 꾸밀 수 있는지 알아볼 거예요.

 

이어서 계속 가볼까요?

 

 

2. 출력의 모든 것: print 함수의 활용법 🖨️

print() 함수는 파이썬에서 데이터를 화면에 출력할 때 가장 많이 사용하는 함수입니다.

단순히 문자열을 출력하는 데만 쓰는 줄 아셨다면… 아직 진짜 잠재력을 모르시는 거예요!

오늘은 줄 바꿈 조절부터 포맷팅, 여러 값 출력까지 print 함수의 다양한 기능들을 낱낱이 파헤쳐볼게요 🕵️‍♀️

기본 사용법: 문자열과 변수 출력하기

name = "지민"
print("안녕하세요,", name, "님!")

print()는 기본적으로 여러 값을 쉼표(,)로 나열하면 자동으로 한 칸씩 띄워서 출력해 줍니다.

편리하긴 하지만, 복잡한 출력 결과를 만들기엔 조금 부족할 수도 있어요.

줄 바꿈 없이 출력하고 싶을 땐? end 매개변수!

print()는 기본적으로 출력한 후 줄 바꿈(\n)을 포함합니다.

하지만 때로는 같은 줄에 여러 출력을 하고 싶을 때가 있죠?

그럴 땐 end 매개변수를 사용해보세요.

for i in range(5):
    print(i, end=" ")

결과는 이렇게 나와요: 0 1 2 3 4.

줄 바꿈 없이 공백 한 칸을 사이에 두고 출력되었죠?

end=의 기본값은 '\n'이지만, 이를 원하는 값으로 바꿔서 출력 형식을 자유롭게 제어할 수 있습니다.

문자열 포맷팅: 깔끔하게 출력하자 💬

print 함수에서 가장 많이 쓰이는 고급 기능이 바로 문자열 포맷팅이에요.

숫자나 문자열을 보기 좋게 출력하려면 아래 방식들을 활용해보세요!

1. f-string (파이썬 3.6 이상)

name = "민수"
age = 24
print(f"{name}님의 나이는 {age}살입니다.")

2. format() 메서드

print("{}님의 나이는 {}살입니다.".format(name, age))

3. % 연산자 방식

print("%s님의 나이는 %d살입니다." % (name, age))

요즘에는 f-string이 가장 많이 쓰이지만, 다양한 포맷을 이해해두면 유지보수할 때 큰 도움이 되죠.

특히 format()은 정렬, 자리수 지정에도 유리하답니다!

print 함수의 다양한 매개변수

매개변수 설명 예시
sep 값들 사이에 출력할 문자 지정 print("2025", "04", "09", sep="-")
end 출력 후 붙을 문자열 지정 print("Hello", end="🌟")
file 출력 대상을 파일로 지정 print("저장", file=f)

이처럼 print 함수는 단순한 출력 도구가 아니라 다양한 형식의 메시지를 효과적으로 전달할 수 있는 강력한 도구입니다.

CLI 기반 프로그램을 만든다면 이 함수 하나만으로도 사용자의 마음을 사로잡을 수 있어요 😉

 

 

3. 텍스트 파일에 쓰기: write와 open 함수 📝

파이썬으로 코딩을 하다 보면 사용자에게 결과를 보여주는 것뿐만 아니라, 그 결과를 파일로 저장하고 싶은 경우가 정말 많습니다.

예를 들면

로그 기록, 설문 결과, 사용자 응답 저장 같은 거요.

그럴 때 사용하는 게 바로 open() 함수와 write() 메서드입니다.

오늘은 이 두 가지를 가지고 텍스트 파일을 어떻게 다루는지 깔끔하게 정리해드릴게요!

open() 함수로 파일 열기 🗂️

파일에 뭔가를 쓰기 위해서는 먼저 파일을 열어야 합니다.

이때 사용하는 함수가 open()이고, 모드를 잘 지정해야 원하는 동작이 가능해요.

파일 모드 설명
"w" 쓰기 모드. 파일이 없으면 새로 만들고, 있으면 기존 내용을 덮어씀
"a" 추가 모드. 기존 파일의 끝에 내용을 덧붙임
"x" 배타적 생성 모드. 파일이 존재하면 오류 발생
f = open("my_log.txt", "w")

위 코드는 my_log.txt라는 파일을 새로 만들거나 기존 내용을 삭제하고 새로 시작합니다.

조심해야겠죠? 데이터를 덮어쓰니까요!

write()로 내용 쓰기 ✍️

파일을 열었으면, 이제 그 안에 내용을 써야죠.

이때 사용하는 게 write() 메서드입니다.

문자열 형태만 쓸 수 있고, 숫자나 리스트는 형 변환을 해야 합니다.

f = open("log.txt", "w")
f.write("첫 번째 로그입니다.\n")
f.write("두 번째 로그입니다.\n")
f.close()

\n은 줄 바꿈을 의미합니다.

write()는 자동 줄바꿈이 없기 때문에 꼭 직접 줄 바꿈 문자를 넣어줘야 해요.

숫자나 리스트를 쓰고 싶을 땐?

score = 100
f.write(str(score) + "\n")

문자열로 바꾼 후에 써야 에러가 나지 않습니다.

str(), join() 등을 적극 활용해 보세요.

write 사용 시 주의할 점 ⚠️

  • write는 문자열만 처리 가능 – 숫자는 str()로 변환
  • 자동 줄바꿈 없음\n을 직접 삽입해야 줄이 나뉨
  • 파일은 꼭 닫기f.close() 또는 with 문 활용

이제 write와 open을 이용해 원하는 데이터를 텍스트 파일로 출력하는 건 문제없겠죠?

다음 단계에서는 반대로 파일을 읽는 방법을 배워볼 차례입니다.

한 줄씩 읽기부터 전체 읽기까지, 실제로 많이 쓰이는 테크닉들을 하나씩 소개해드릴게요!

 

 

4. 텍스트 파일 읽기: readline, readlines, read 차이점 📄

자, 지난 시간에는 우리가 파일에 데이터를 쓰는 방법에 대해 배웠죠?

그렇다면 이번에는 반대로 텍스트 파일에서 데이터를 읽는 법에 대해 이야기해볼게요.

실제 현업이나 실습 중에는 기존에 저장된 데이터를 다시 불러와서 분석하거나 조건에 따라 처리해야 할 때가 많아요.

이럴 때 자주 쓰이는 방법이 바로 readline(), readlines(), read()입니다.

readline(): 한 줄씩 읽기 🧾

readline() 함수는 파일에서 한 줄씩 차례대로 읽어옵니다.

반복문과 함께 자주 사용되며, 메모리를 적게 사용해서 대용량 파일 처리에 유리해요.

f = open("log.txt", "r")
while True:
    line = f.readline()
    if not line:
        break
    print(line, end='')
f.close()

end=''print()의 자동 줄 바꿈을 막기 위해 넣은 거예요.

파일 자체에 줄바꿈이 포함되어 있기 때문에 중복 줄바꿈을 피하려는 의도랍니다.

readlines(): 전체 줄을 리스트로 가져오기 📋

readlines()는 파일의 모든 줄을 한꺼번에 읽어서 리스트로 반환합니다.

각 줄은 리스트의 요소가 되고, \n도 포함되어 있어요.

f = open("log.txt", "r")
lines = f.readlines()
for line in lines:
    print(line, end='')
f.close()

파일 전체를 메모리에 올리기 때문에 작은 파일에 적합하며, 각 줄을 배열처럼 다루고 싶을 때 유용해요.

read(): 파일 전체를 하나의 문자열로 읽기 📜

read()는 파일 전체를 하나의 문자열로 읽어옵니다.

텍스트 분석, 웹 크롤링 후 가공 등에 많이 사용돼요.

f = open("log.txt", "r")
data = f.read()
print(data)
f.close()

모든 줄이 하나의 문자열에 포함되므로 줄 단위로 처리하려면 splitlines()split("\n")을 써야 해요.

📊 함수별 비교표

함수 동작 방식 적합한 상황
readline() 한 줄씩 읽음 대용량 파일
readlines() 전체 줄을 리스트로 작은 파일, 리스트 처리
read() 전체 내용을 문자열로 문자열 가공, 정규표현식

세 가지 방법을 잘 이해하면 상황에 맞게 효율적인 파일 처리가 가능해져요.

다음 섹션에서는 파일을 열고 닫는 과정을 더 안전하게 다룰 수 있는 with 문에 대해 설명해드릴게요.

지금까지 배운 내용보다 더 깔끔한 코드, 기대되시죠? 😊

 

 

5. 파일 다룰 때 꼭 써야 할 with 문 📂

이전 단계들에서 open()으로 파일을 열고, read()write()로 읽고 쓰고, 마지막에 f.close()로 파일을 닫는 흐름을 배웠죠?

그런데 혹시라도 파일을 열었는데 닫는 걸 깜빡하거나, 중간에 오류가 발생해서 close()가 실행되지 않았다면 어떻게 될까요? 😨

바로 메모리 누수, 리소스 낭비 같은 문제가 생기게 됩니다.

이 문제를 깔끔하게 해결해주는 도구가 바로 with 문이에요.

파이썬에서는 Context Manager라는 기능을 통해 특정 작업이 끝나면 자동으로 정리(clean-up)를 해주는 구조를 제공하는데, 파일 처리에서는 거의 무조건 with open()을 사용하는 것이 좋습니다.

with 문 기본 구조

with open("log.txt", "r") as f:
    data = f.read()
    print(data)

with open(...) as 변수: 형태로 작성하면, with 블록이 끝나는 시점에서 자동으로 close()가 호출됩니다.

더 이상 f.close()를 직접 쓰지 않아도 된다는 거죠!

with 문으로 파일 쓰기 예시

with open("output.txt", "w") as f:
    f.write("파이썬은 정말 재밌어요!\n")
    f.write("with 문 너무 편하다...\n")

위처럼 파일을 쓰는 작업도 간단하게 처리할 수 있습니다.

코드도 깔끔해지고, 실수할 여지도 줄어들죠.

with 문으로 한 줄씩 파일 읽기

with open("log.txt", "r") as f:
    for line in f:
        print(line, end='')

놀랍게도 파일 객체 자체가 반복 가능한 구조이기 때문에 for 문과 함께 쓰면 자동으로 줄 단위 읽기가 가능합니다.

이 방식은 readline()보다 더 간단하고 안전한 패턴으로, 가장 권장되는 형태예요.

파일 쓰기와 예외 처리를 함께 쓰고 싶다면?

with 문은 try-except 구문과도 잘 어울립니다.

예외가 발생하더라도 파일이 자동으로 닫히기 때문에 코드 안정성을 높일 수 있어요.

try:
    with open("log.txt", "r") as f:
        print(f.read())
except FileNotFoundError:
    print("파일이 존재하지 않아요 😥")

with 문 사용 시 장점 요약 ✨

  • 자동으로 파일을 닫아줌 – close()를 깜빡해도 OK!
  • 코드 가독성 향상 – 들여쓰기 구조가 명확해짐
  • 에러 발생에도 안전함 – 자원 누수 방지

이제 여러분도 자신 있게 with open()을 사용할 수 있겠죠? 😎

 

다음 단계에서는 마지막으로 파일 입출력 중 발생할 수 있는 예외 처리에 대해 소개할게요.

정말 자주 마주치는 오류들, 어떻게 깔끔하게 넘기는지 알려드릴게요!

 

 

6. 파일 입출력 중 발생할 수 있는 예외 처리법 ⚠️

현실은 늘 그렇죠.

코드가 잘 작동하리라는 믿음은 좋지만, 언제든 오류는 발생할 수 있어요.

특히 파일을 다룰 때는 파일이 존재하지 않거나, 권한이 없거나, 파일이 이미 열려 있거나…

이런 문제가 수두룩하죠.

그래서 꼭 필요한 게 바로 예외 처리입니다!

try-except 문으로 오류 막기 🛡️

예외 처리의 기본은 try-except 구문입니다.

파일을 열거나 쓸 때 문제가 발생해도 프로그램이 강제 종료되지 않도록 막아주는 거죠.

try:
    with open("user_info.txt", "r") as f:
        print(f.read())
except FileNotFoundError:
    print("파일을 찾을 수 없습니다 😢")

위 예시는 가장 자주 쓰이는 FileNotFoundError를 처리한 예입니다.

사용자가 없는 파일명을 입력할 수도 있잖아요?

finally 문: 무조건 실행되는 블록 💡

try:
    f = open("log.txt", "r")
    print(f.read())
except:
    print("에러 발생!")
finally:
    f.close()
    print("파일을 닫았습니다.")

finally는 예외 발생 여부와 관계없이 실행돼요.

자원을 정리할 때 아주 유용하죠. 특히 직접 close()를 사용할 때 이 구조가 유용합니다.

다양한 예외 처리 팁 모음 ✨

  • FileNotFoundError – 파일이 존재하지 않을 때
  • PermissionError – 쓰기/읽기 권한 없을 때
  • IsADirectoryError – 디렉터리를 파일처럼 열었을 때

예외를 정확하게 구분해서 처리하면 사용자에게 친절한 메시지를 줄 수 있고, 프로그램도 더 안정적이 됩니다. 게다가 예외 메시지를 로그로 저장하면 디버깅에도 큰 도움이 되죠!

 

 


마무리 🧩

자, 여기까지 따라오신 여러분! 👏

이제 파이썬의 표준 입출력에 대해 완전히 정복하셨다고 해도 과언이 아닙니다.

input(), print()부터 시작해서 open(), with 문, 파일 읽기/쓰기, 그리고 예외 처리까지.

이 모든 흐름을 익히면 단순한 텍스트 기반 프로그램부터 데이터 로깅, 사용자 응답 시스템까지 얼마든지 만들 수 있어요.

 

궁금하시다면 블로그 구독과 댓글, 좋아요도 부탁드려요! 😊

반응형

+ Recent posts