티스토리 뷰
0. 클래스와 함수
- 함수는 동작만
- 클래스는 함수+상태 저장 가능
1. 상속 : 같은 기능인데 이름만 다름 => 중복 방지
- 예: 좋아요, 싫어요 기능
class Like:
def __init__(self, post, user):
self.post = post
self.user = user
class Sad:
def __init__(self, post, user):
self.post = post
self.user = user
# 공통된 부모 클래스를 만들어줌
class React:
def __init__(self, type, post, user):
self.type = type
self.post = post
self.user = user
# like와 sad는 react를 상속 받음
class Like(React):
def __init__(self, post, user):
super().__init__("LIKE", post, user)
class Sad(React):
def __init__(self, post, user):
super().__init__("SAD", post, user)
2. 추상적인 부모 클래스 : 직접 인스턴스를 만들지 않고, 자식 클래스를 만들때만 사용(상속할 때만 사용), 의미를 갖지 X
- 파이썬은 추상적인 부모 클래스를 나타낼 방법이 없다 => 개발자의 몫으로 남겨둠 (Java에서는 abstract 클래스)
* 파이썬은 빠르게 프로그래밍 할 수 있는 대신, 많은 약속을 생략함
- 왜 이렇게 할까? 전체적인 코드의 구조를 유지하기 위해
1) 명확한 역할 분리, 구조화: 추상 클래스는 "공통 구조", 자식 클래스는 "구체 행동"
# 추상적인 부모클래스를 이용해 인스턴스를 만들지 않음
## 이렇게 안씀
reaction = Reaction("sdfksdfls", post, me)
# 반드시 구체적인 자식 클래스로 사용
like = Like(post, me)
2) 유지보수: 오타가 나거나 의미없는 문자를 입력해도 코드상에 에러가 없어 디버깅이 어렵다
# 예시
reaction = Reaction("Liek", post, me) # 오타났는데 코드상 에러 없음
3) 확장성: 메서드가 달라야 한다면, if문을 잔뜩 써야하는 등의 문제가 있으나 클래스로 나누면 깔끔하게 분리 가능
class Like(Reaction):
def display(self):
return "좋아요"
class Dislike(Reaction):
def display(self):
return "싫어요"
3. reaction = Reaction("sdfksdfls", post, me) 식으로 구현했을때
class Reaction:
def __init__(self, kind, post, user):
self.kind = kind
self.post = post
self.user = user
def display(self):
if self.kind == "Like":
return "좋아요"
elif self.kind == "Dislike":
return "싫어요"
else:
return "알 수 없음"
reactions = [
Reaction("Like", "Post1", "UserA"),
Reaction("Dislike", "Post1", "UserB"),
Reaction("Liek", "Post1", "UserC") # 오타인데도 실행됨! 버그 발생
]
for r in reactions:
print(r.display())
4. 객체지향 방식: 자식 클래스로 분리
from abc import ABC, abstractmethod
class Reaction(ABC):
def __init__(self, post, user):
self.post = post
self.user = user
@abstractmethod # 틀만 있고 내용은 없음 => 자식 클래스에서 구현해야함
def display(self):
pass
class Like(Reaction):
def display(self):
return "좋아요"
class Dislike(Reaction):
def display(self):
return "싫어요"
reactions = [Like("Post1", "UserA"), Dislike("Post1", "UserB")]
for r in reactions:
print(r.display())
5. @abstractmethod (추상메서드)
- 자식 클래스가 반드시 구현해야하는 메서드를 지정
- 왜 쓸까? 클래스를 설계도처럼 만들고 싶을때, 공통 메서드와 이름은 정해두되, 행동은 자식이 정하게 하고 싶을때
- @abstractmethod를 사용하면, 부모 클래스로 인스턴스 생성할 수 없고, 자식클래스에 해당 메서드를 구현해야함
from abc import ABC, abstractmethod
class Reaction(ABC):
def __init__(self, kind, post, user):
self.kind = kind
self.post = post
self.user = user
@abstractmethod
def sound(self):
pass
# a = Reaction("Good","좋아","goody") # error , 자식 클래스 생성해야함
class Like(Reaction):
def __init__(self, post, user):
super().__init__("LIKE", post, user)
# b = Like("좋아용","하잉") # 에러, 자식클래스에 sound 정의해줘야 함
class Sad(Reaction):
def __init__(self, post, user):
super().__init__("SAD", post, user)
def sound(self):
return "흑흑"
c = Sad("슬픈날","닉네임")
print(c.sound()) # 흑흑
6. 보통은 같은 메소드를 쓰는데 간혹 예외가 필요한 경우:오버라이딩(부모 함수 수정)
class Logger:
def log(self, message):
print(f"[LOG] {message}") # 기본 로그는 콘솔 출력
class FileLogger(Logger):
def log(self, message):
with open("log.txt", "a") as f:
f.write(f"[FILE] {message}\n") # 파일에 저장
7. 클래스 변수(모든 인스턴스가 공유)와 인스턴스 변수(인스턴스 내에서 독립적으로 사용)
class Test:
num = 0 # 클래스 변수
def wrong_change(self):
num = 5 # wrong_chagen 내에서만 쓰는 지역 변수임
def instance_change(self):
self.num = 6 # 값을 직접 대입=> 인스턴스 변수가 새로 생성됨
def class_change(self):
Test.num = 7 # 클래스 변수 바뀜(인스턴스 아님)
a = Test()
b = Test()
a.wrong_change() # class num에는 아무일도 안일어남
print(a.num) # 0
print(b.num) # 0
a.instance_change() # 인스턴스 a의 값 바꿈 => a의 num은 더이상 클래스변수가 아니고 인스턴스 변수임
print(a.num) # 6
print(b.num) # 0
a.class_change()
print(a.num) # 6
print(b.num) # 7
8. 클래스 내의 리스트
class Test:
data = [] # 클래스 변수
def wrong_change(self):
item = "apple" # wrong_chagen 내에서만 쓰는 지역 변수임
data = [item]
def instance_change(self):
self.data = [] # 인스턴스 전용 리스트가 생성됨
self.data.append("banana")
def class_change(self):
Test.data.append("carrot") # 클래스 변수 바뀜(인스턴스 아님)
a = Test()
b = Test()
a.wrong_change() # class data에는 아무일도 안일어남
print(a.data) # []
print(b.data) # []
a.instance_change() # 인스턴스 a의 data 수정 => a는 더이상 data를 클래스 data를 쓰지않고 독립적으로 유지
print(a.data) # ['banana'] # 인스턴스를 수정한
print(b.data) # []
a.class_change()
print(a.data) # ['banana']
print(b.data) # ['carrot']
- 만약 instance_change에 self.data = [ ] 로 초기화 하지 않는다면?
class Test:
data = [] # 클래스 변수
def wrong_change(self):
item = "apple" # wrong_chagen 내에서만 쓰는 지역 변수임
data = [item]
def instance_change(self):
self.data.append("banana") # self.data =[]로 초기화하지 않고 "변경"만해 클래스 변수를 가리킴
def class_change(self):
Test.data.append("carrot") # 클래스 변수 바뀜(인스턴스 아님)
a = Test()
b = Test()
a.wrong_change() # class data에는 아무일도 안일어남
print(a.data) # []
print(b.data) # []
a.instance_change() # 클래스 리스트 수정
print(a.data) # ['banana']
print(b.data) # ['banana']
a.class_change() # 클래스 리스트 수정
print(a.data) # ['banana', 'carrot']
print(b.data) # ['banana', 'carrot']
- 정리: 대입(=)하면 인스턴스 속성이 새로 생기고, 수정(append, update 등)만 하면 기존 클래스 변수를 그대로 공유
class Test:
num = 0
data = []
a = Test()
b = Test()
a.num = 5
a.data.append(1)
print(a.num) # 5
print(b.num) # 0
print(a.data) # [1]
print(b.data) # [1]
'AI > Python' 카테고리의 다른 글
[Python] Json과 집합(set), CSV, assert(), 클로저, lambda, map, filter (0) | 2025.04.01 |
---|---|
[Python] 부동소수점, 숫자 반올림 (0) | 2025.03.27 |
[Python] 문자열의 메소드, 문자열을 숫자로, 지수표현 (0) | 2025.03.27 |
[Python] 모듈과 패키지, 내장함수 (0) | 2025.03.26 |
[Python] 자료형 (0) | 2025.03.04 |
- Total
- Today
- Yesterday
- 다이어트
- 미라클모닝
- 스크랩
- 영어회화
- 오픽
- C언어
- 빅데이터 분석기사
- 30분
- 기초
- 아침운동
- Ai
- 뉴스
- ChatGPT
- 습관
- 갓생
- 프로그래머스
- 고득점 Kit
- 루틴
- Python
- opic
- SQL
- 오블완
- IH
- 티스토리챌린지
- 실기
- 줄넘기
- 경제
- 운동
- 아침
- llm
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |