| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
- TTS
- Transformer
- python 기초
- 정보처리기사
- CLIP
- 트랜스포머
- SQL
- 딥러닝
- dementional reduction
- 캐글
- Python
- 데이터 시각화
- 소프트웨어 개발
- 자연어처리
- UMAP
- 데이터엔지니어
- CNN
- 머신러닝
- 랭그래프
- 기초
- python기초
- LangGraph
- 에이전트
- ASR
- 객체지향
- RDBMS
- 힙정렬
- 생성형 인공지능
- 알고리즘
- RNN
- Today
- Total
수달이네 기술 블로그
3. 파이썬 매직 메서드, 객체지향, 예외처리 본문
더블 언더스코어(__)로 시작하고 끝나는 메서드 이름을 갖는 메서드들
특정 구문, 내장함수를 사용할 때 파이썬 인터프리터에 의해 자동으로 호출된다.
repr
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return f"Dog(name='{self.name}', age={self.age})"
Rucy = Dog('루시', 15)
print(repr(Rucy))
print(Rucy)
# Dog(이름='루시', 나이=15)
# Dog(이름='루시', 나이=15)
위처럼 객체값을 출력할 때 나오는 값을 정해준다.
eval()
주어진 문자열을 파이썬 표현식으로 인식하고 실행하여 결과를 반환
x = 10
y = 3
result = x + y
print(result)
result = eval("x + y")
print(result)
# 13
# 13
이걸 이용하여
위의 repr을
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return f"Dog(name='{self.name}', age={self.age})"
위와 같이 변수명과 같이 넣어준다면,
rucy_repr = repr(rucy)
result = eval(rucy_repr)
위와 같이 객체를 생성해 줄수도 있으며 해당 객체는
print(result)
print(result == rucy)
# Dog(name='루시', age=15)
# False
실제로 작동하며, 원래 rucy와 다른 객체로 나오게 된다.
str()
class Book:
def __init__(self, title):
self.title = title
book = Book('미친듯이 재밌는 파이썬')
print(book)
print(str(book))
# <__main__.Book object at 0x0000021785611D30>
# <__main__.Book object at 0x0000021785611D30>
class Book:
def __init__(self, title):
self.title = title
def __str__(self):
return self.title
book = Book('미친듯이 재밌는 파이썬')
print(book)
print(str(book))
# 미친듯이 재밌는 파이썬
# 미친듯이 재밌는 파이썬
위처럼 객체값을 출력할 때 나오는 값을 정해준다.
그러나 __repr__과의 차이점은 repr의 경우 개발자가 실제 객체가 뭔지 알기 위해 사용하는 것인데,
__str__의 경우 사용자가 원하는 내용을 찍어주고 싶을 때 사용한다. 즉, 객체의 내용이 중요하지 않다.
그렇다면 두 함수 모두 있을때는?
- str이 없으면 repr을 출력.
- str이 있으면 str을 출력
class Book:
def __init__(self, title):
self.title = title
def __str__(self):
return f"str='{self.title}'"
def __repr__(self):
return f"repr='{self.title}'"
# str='미친듯이 재밌는 파이썬'
# str='미친듯이 재밌는 파이썬'
len()
클래스의 길이를 반환해주는 함수
class Queue:
def __init__(self):
self.items = [1, 2, 3, 4, 5]
def __len__(self):
return len(self.items)
li = [1, 2, 3, 4, 5]
print(len(li))
print(li)
queue = Queue()
print(queue)
print(len(queue))
# 5
# [1, 2, 3, 4, 5]
# <__main__.Queue object at 0x0000021785612A50>
# 5
위처럼 원래 구현되지 않은 len함수를 작동되도록 한다.
getitem()
파이썬에서 인덱싱을 지원하기 위해 사용하는 메소드
- 객체의 특정 인덱스 혹은 키를 반환한다.
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
pt = Point(5, 3)
print(pt)
print(pt[0])
print(pt[1])
print(pt[-100])
# <__main__.Point object at 0x0000021785612BA0>
#---------------------------------------------------------------------------
# TypeError: 'Point' object is not subscriptable
만약 인덱스를 사용하고 싶어서 위처럼 사용할 경우 오류가 생기는 것을 볼 수 있다
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __getitem__(self, index):
if index == 0:
return self.x
elif index == 1:
return self.y
else:
return -1
pt = Point(5, 3)
print(pt)
print(pt[0])
print(pt[1])
print(pt[-100])
# <__main__.Point object at 0x0000021785612CF0>
# 5
# 3
# -1
위처럼 여러 변수가 담긴 클래스를 인덱스로 변수 하나하나 가져올 수 있다.
call()
파이썬에서 객체를 함수처럼 호출할 수 있는 메서드
class CallableObject:
pass
coj = CallableObject()
coj()
# ---------------------------------------------------------------------------
# TypeError: 'CallableObject' object is not callable
당연히 위처럼 함수를 부르는 것은 불가능 하다. 하지만
class CallableObject:
def __call__(self, *args, **kwargs):
print(f'args:{args}, kwargs:{kwargs}')
coj = CallableObject()
coj(1,2,3, a = 'A', b = 'B')
# args:(1, 2, 3), kwargs:{'a': 'A', 'b': 'B'}
위처럼 argument와 keyward argument를 이용하여 함수를 만들어줄 수 있다.
파이썬 객체지향의 4대 패러다임
캡슐화(Encapsulation)
객체 안에 데이터(속성)와 메서드(함수)를 감추고, 외부에 필요한 기능만 제공하는 것
왜 캡슐화가 필요한가?
- 보안: 다른데서 객체를 생성한 후 값을 임의로 넣어 잘못된 결과를 만들 수 있다.
- 위로 인해 코드가 오류가 생길수도 있다.
class Animal:
def __init__(self, name, age):
self.name = name
self.__age = age # __로 시작하면 private 속성
def get_age(self):
return self.__age
def set_age(self, age):
if age > 0:
self.__age = age
else:
print("나이는 양수여야 합니다.")
파이썬에서는 private속성으로 만들기 위해서는 __변수명을 이용한다.
직접 접근은 불가하지만 접근하기 위해서 get메서드를 만들어 접근할 수 있으며, set메서드를 만들어 넣어줄 수 있다.
class Animal:
def __init__(self, name, age):
self.name = name
self.__age = age # __로 시작하면 private 속성
def get_age(self):
return self.__age
def set_age(self, age):
if age > 0:
self.__age = age
else:
print("나이는 양수여야 합니다.")
class Dog(Animal):
def __init__(self, name, age, breed):
super().__init__(name, age)
self.breed = breed
def bark(self):
print(f"{self.name}가 멍멍 짖습니다!")
# 사용 예
dog = Dog("루시", 15, "포메")
dog.bark() # 루시가 멍멍 짖습니다!
print(dog.name) # 루시
print(dog.breed) # 포메
print(dog.get_age())
dog.set_age(14)
print(dog.get_age()) # 14
dog.__age = 100 # 외부에서 수정 시도 (실제 속성은 바뀌지 않음)
print(dog.get_age()) # 여전히 14
# 루시가 멍멍 짖습니다!
# 루시
# 포메
# 15
# 14
# 14
위처럼 사용 가능하다
상속(inheritance)
기존 클래스(부모)의 속성과 기능을 새로운 클래스(자식)가 물려받아 재사용하는 것
class Animal:
def speak(self):
print("동물이 소리를 냅니다.")
class Dog(Animal):
def speak(self):
print("멍멍!")
# 사용 예
a = Animal()
a.speak() # 동물이 소리를 냅니다.
rucy = Dog()
rucy.speak() # 멍멍! (부모 메서드를 오버라이딩)
부모 클래스의 메서드를 자식 클래스가 물려받아 사용
다형성 (Polymorphism)
동일한 이름의 메서드가 상황에 따라 다르게 동작할 수 있는 것
class Cat:
def speak(self):
print("야옹!")
class Dog:
def speak(self):
print("멍멍!")
def make_sound(animal):
animal.speak()
# 사용 예
c = Cat()
d = Dog()
make_sound(c) # 야옹!
make_sound(d) # 멍멍!
같은 이름의 메서드지만 다른 함수가 작동한다.
추상화 (Abstraction)
핵심 개념만 정의하고, 구체적인 내용은 자식 클래스에서 채우도록 설계하는 것 (설계의 틀 제공)
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def speak(self):
pass # 추상 메서드, 자식이 반드시 구현해야 함
class Dog(Animal):
def speak(self):
print("멍멍!")
class Cat(Animal):
def speak(self):
print("야옹!")
rucy = Dog()
rucy.speak() # 멍멍!
@abstractmethod: 추상 메서드를 생성
- 이걸 상속받는 클래스는 반드시 해당 메서드를 구현해야한다.
왜 이걸 사용할까?
- 한 회사가 기능 하나를 만들었을 때
- 다른 회사에서 해당 모듈을 사용하여 상속하고, 오버라이딩하여, 그 회사가 가진 정보를 넣어 작동하도록 만들어 줄 수 있다.
예외
print(10 / 3)
print(5 / 0) # ZeroDivisionError: division by zero
print(4 / 2)
파이썬은 에러가 날 경우 다음 실행할 코드가 실행되지 않는다.
만약 이게 서버일 경우, 여러 사용자가 사용하던 중 한 사용자가 이상행동을 하여 오류가 나면, 서버가 닫히며 모든 사용자가 사용 못하게 될 것이다.
- 이걸 막기 위해 예외처리를 이용해 프로그램을 종료하지 않고 다음 코드를 낼 수 있도록 만든다.
예외 발생 경우
ValueError
- 잘못된 값을 함수나 연산에 제공할 때 발생합니다.
- 예) 숫자가 아닌 문자열을 int() 함수로 변환하려고 할 때 발생.
TypeError
- 올바르지 않은 유형의 객체를 연산에 사용하려 할 때 발생합니다.
- 예) 문자열과 숫자를 함께 더하려고 할 때 발생.
ZeroDivisionError
- 숫자를 0으로 나누려고 할 때 발생합니다.
IndexError
- 리스트, 튜플, 문자열 등의 시퀀스 유형에서 범위를 벗어난 인덱스에 접근하려 할 때 발생합니다.
- 예) 길이가 3인 리스트에 대해 4번째 요소에 접근하려고 할 때 발생.
KeyError
- 딕셔너리에서 존재하지 않는 키를 사용하여 값을 검색하려고 할 때 발생합니다.
AttributeError
- 객체에 없는 속성이나 메서드에 접근하려고 할 때 발생합니다.
FileNotFoundError
- 존재하지 않는 파일을 열려고 할 때 발생합니다.
ImportError
- 존재하지 않는 모듈을 가져오려고 할 때 또는 모듈 내에 해당 속성/함수가 없을 때 발생합니다.
NameError
- 정의되지 않은 변수나 함수를 사용하려고 할 때 발생합니다.
- 예) 프로그램에서 정의되지 않은 변수 x를 사용하려고 할 때 발생.
OverflowError
- 수치 연산 결과가 너무 커서 표현할 수 없을 때 발생합니다.
MemoryError
- 프로그램이 사용 가능한 모든 메모리를 소진했을 때 발생합니다.
try:
# 예외가 발생할 가능성이 있는 코드
except ExceptionType1: # 'ExceptionType1'에는 실제 예외 유형이 들어갑니다.
# ExceptionType1 예외가 발생했을 때 실행될 코드
except ExceptionType2: # 'ExceptionType2'에는 다른 예외 유형이 들어갑니다.
# ExceptionType2 예외가 발생했을 때 실행될 코드
# 추가적인 except 블록을 계속 추가할 수 있습니다.
else:
# try 블록에서 예외가 발생하지 않았을 때 실행될 코드
finally:
# 예외 발생 여부와 관계없이 항상 실행될 코드
위와 같이 생성할 수 있다.
- exceptionType이 생략될 경우 모든 오류를 받아들인다
except Exception:
- 이것과 같은 내용
try:
print(10 / 3)
print(5 / 0)
print(4 / 2)
except ZeroDivisionError:
print('예외가 발생했어요')
print('프로그램을 종료합니다')
finally
def hi():
try:
data = [10, 20, 30, 40, 50]
print(data[5])
except IndexError as e:
print(e)
return
except ValueError as e:
print(e)
except ZeroDivisionError as e:
print(e)
return
except Exception as e:
print(e)
else:
print('에러가 발생하지 않은 정상적인 프로그램')
finally:
print('에러에 관계없이 무조건 실행되는 문장')
print('프로그램을 종료합니다')
hi()
# list index out of range
# 에러에 관계없이 무조건 실행되는 문장
위와같은 상황에서 보면 return 이 불러와져 나가야 하지만 finally를 부르고 나간다.
이처럼 오류가 발생하든 안하든 무조건 실행하는 문장이 finally이다
'언어 > Python' 카테고리의 다른 글
| 0.모듈 (0) | 2025.11.12 |
|---|---|
| 1. 파이썬 객체지향 (0) | 2025.11.05 |
| 2. 파이썬에서의 상속 (0) | 2025.11.05 |
| 17. 스레드 (0) | 2025.09.04 |
| 16. 이터레이터, 제너레이터 (0) | 2025.09.03 |