728x90
01. 소멸자(destructor)
- 인스턴스가 소멸될 때 자동으로 호출되는 메서드 ##인스턴스(어느 클래스의 객체)==객체(클래스에서뽑아져나오는 덩어리)
class Sample:
def __del__(self):
print("인스턴스가 소멸됩니다")
sample_instance = Sample()
del sample_instance
인스턴스가 소멸됩니다
02. isinstance()
- 객체가 어떤 클래스로부터 만들어졌는지 확인할 수 있는 함수
- 첫 번째 매개변수에 객체, 두 번째 매개변수에 클래스를 입력
- isinstance(객체, 클래스)
- 객체가 해당 클래스를 기반으로 만들어졌으면 True, 관계 없으면 False를 반환
class Student:
def __init__(self):
pass
student = Student()
isinstance(student, Student)
True
- student는 Student클래스를 기반으로 만들었으므로 True
- 리스트 내부에 여러 종류의 객체가 들어있을 때 인스턴스들을 구분하며 속성과 기능을 사용할 때 사용
class Student:
def study(self):
print("공부를 합니다")
class Teacher:
def teach(self):
print("학생을 가르칩니다")
classroom = [Student(), Student(), Teacher(), Student(), Student()]
# 반복을 적용해서 적절한 함수를 호출
for person in classroom:
if isinstance(person, Student):
person.study()
elif isinstance(person, Teacher):
person.teach()
공부를 합니다
공부를 합니다
학생을 가르칩니다
공부를 합니다
공부를 합니다
특수한 이름의 메서드
- __<이름>__() 형태의 메서드들은 특수한 상황에 자동으로 호출되도록 만들어짐
※마크다운에서 __는 볼드이므로 역슬래시로 이스케이프 해줘야함
- 파이썬이 클래스를 사용할 때 제공해주는 보조 기능
03. __str__()
- str() 함수의 매개변수로 객체를 넣으면 호출되는 메소드
- 객체를 문자열로 변환
class Student:
def __init__(self, name, korean, math, english, science):
self.name = name
self.korean = korean
self.math = math
self.english = english
self.science = science
def get_sum(self):
return self.korean + self.math + self.english + self.science
def get_average(self):
return self.get_sum() / 4
def __str__(self):
return f"{self.name}\t{self.get_sum()}\t{self.get_average()}"
students = [Student("윤인성", 87, 98, 88, 95),
Student("연하진", 92, 98, 96, 98),
Student("구지연", 76, 96, 94, 90)]
print("이름", "총점", "평균", sep = "\t") ##sep:seperator(구분자의 초기값은 " ")
for i in students:
print(str(i))
이름 총점 평균
윤인성 368 92.0
연하진 384 96.0
구지연 356 89.0
04. 크기 비교 메서드
이름 | 영어 | 설명 |
eq | equal | 같다 |
ne | not equal | 다르다 |
gt | grater than | 크다 |
ge | grater than or equal | 크거나 같다 |
lt | less than | 작다 |
le | less than or equal | 작거나 같다 |
class Student:
def __init__(self, name, korean, math, english, science):
self.name = name
self.korean = korean
self.math = math
self.english = english
self.science = science
def get_sum(self):
return self.korean + self.math + self.english + self.science
def get_average(self):
return self.get_sum() / 4
def __str__(self):
return f"{self.name}\t{self.get_sum()}\t{self.get_average()}"
def __eq__(self, value):
return self.get_sum() == value.get_sum()
def __ne__(self, value):
return self.get_sum() != value.get_sum()
def __gt__(self, value):
return self.get_sum() > value.get_sum()
def __lt__(self, value):
return self.get_sum() < value.get_sum()
def __le__(self, value):
return self.get_sum() <= value.get_sum()
student_a = Student("나선주", 98, 92, 96, 92)
student_b = Student("윤아린", 95, 98, 98, 98)
student_a == student_b
False
student_a != student_b
True
# student_a.__gt__(student_b)
student_a > student_b
False
student_a < student_b
True
- 비교할 때 사용하는 자료형을 한정하고 싶다면 예외발생을 활용할 수도 있음
student_a < 100
class Student:
def __init__(self, name, korean, math, english, science):
self.name = name
self.korean = korean
self.math = math
self.english = english
self.science = science
def get_sum(self):
return self.korean + self.math + self.english + self.science
def get_average(self):
return self.get_sum() / 4
def __str__(self):
return f"{self.name}\t{self.get_sum()}\t{self.get_average()}"
def __eq__(self, value):
if not isinstance(value, Student):
raise TypeError("Student 클래스의 인스턴스만 비교할 수 있습니다")
return self.get_sum() == value.get_sum()
def __ne__(self, value):
return self.get_sum() != value.get_sum()
def __gt__(self, value):
return self.get_sum() > value.get_sum()
def __lt__(self, value):
return self.get_sum() < value.get_sum()
def __le__(self, value):
return self.get_sum() <= value.get_sum()
student_a = Student("나선주", 98, 92, 96, 92)
student_a == 10
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[39], line 1
----> 1 student_a == 10
Cell In[37], line 20, in Student.__eq__(self, value)
18 def __eq__(self, value):
19 if not isinstance(value, Student):
---> 20 raise TypeError("Student 클래스의 인스턴스만 비교할 수 있습니다")
21 return self.get_sum() == value.get_sum()
TypeError: Student 클래스의 인스턴스만 비교할 수 있습니다
05. 클래스 변수와 클래스 메소드
- 객체가 변수와 메소드를 가지는 것 처럼 클래스도 변수와 메소드를 가질 수 있음
class Korean:
country = "한국" # 클래스 변수 country
def __init__(self, name, age, address):
country = "한국"
self.name = name # 인스턴스 변수 self.name
self.age = age
self.address = address
man = Korean("홍길동", 35, "서울")
man.name
'홍길동'
Korean.name ###클래스는 인스턴스변수에 접근할 수 없다 ##인스턴스는 클래스에 접근할 수 있다(전역변수와 지역변수처럼)
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
Cell In[48], line 1
----> 1 Korean.name
AttributeError: type object 'Korean' has no attribute 'name'
man.country
'한국'
Korean.country
'한국'
class Person:
bag = []
def put_bag(self, stuff):
Person.bag.append(stuff)
#self.bag을 사용하면 인스턴스 변수와 혼동하기 쉽기 때문에 클래스 이름을 사용하는것을 권장
#self.bag.append(stuff) 상기와 같은 코드
james = Person()
james.put_bag("책")
maria = Person()
maria.put_bag("열쇠")
print(james.bag)
print(maria.bag)
print(Person.bag)
['책', '열쇠']
['책', '열쇠']
['책', '열쇠']
class Person:
bag = []
def __init__(self):
self.bag = []
def put_bag(self, stuff):
Person.bag.append(stuff) #클래스변수의 bag
def put_mybag(self, stuff):
self.bag.append(stuff) # 인스턴트 변수(self)의 bag
james = Person()
james.put_mybag("책")
james.put_bag("사전")
maria = Person()
maria.put_mybag("열쇠")
maria.put_bag("자물쇠")
# 같은 이름의 인스턴스 변수와 클래스 변수가 존재할 때는 인스턴스 변수 우선
print(james.bag)
print(maria.bag)
print(Person.bag)
['책']
['열쇠']
['사전', '자물쇠']
클래스 메서드
- 인스턴스 또는 클래스로 호출
- 생성된 인스턴스가 없어도 호출 가능
- @classmethod 데코레이터를 표시하고 작성
- 매개변수 cls를 사용
- 클래스.메소드()의 형태로 사용
- 인스턴스 변수에 접근할 수 없지만 클래스 변수에는 접근 가능
- 메서드의 실행이 외부상태에 영향을 미치지 않는 순수함수를 만들 때
- 인스턴스의 상태를 변화시키지 않는 메서드를 만들 때
class Korean:
country = "한국"
@classmethod
def trip(cls, country):
if cls.country == country:
print("국내여행")
else:
print("해외여행")
Korean.trip("한국")
국내여행
Korean.trip("미국")
해외여행
가비지 컬렉터(garbage collector)
- 프로그램 내부에서 무언가 생성한다는 것은 메모리에 올린다는 의미
- 메모리가 부족해지면 컴퓨터는 하드디스크를 메모리처럼 사용
- 이런 동작을 스왑(swap)이라고 함
- 하드디스크는 메모리보다 훨씬 느리기 때문에 스왑을 처리하는 속도도 느림
- 프로그램에서 변수를 만들면 메모리에 데이터가 올라가고, 계속 만들게 되면 메모리가 가득 참
- 파이썬에서는 가비지 컬렉터가 더 사용할 가능성이 없는 데이터(변수에 저장되지 않은 데이터)를 메모리에서 제거해서 메모리를 정리
- 메모리가 부족해지면 컴퓨터는 하드디스크를 메모리처럼 사용
# 변수에 저장하지 않은 경우
class Test:
def __init__(self, name):
self.name = name
print(f"{self.name} - 생성되었습니다")
def __del__(self):
print(f"{self.name} - 파괴되었습니다")
Test("A")
Test("B")
Test("C")
A - 생성되었습니다
A - 파괴되었습니다
B - 생성되었습니다
B - 파괴되었습니다
C - 생성되었습니다
[43]:
<__main__.Test at 0x216888dbfe0>
# 변수에 저장한 경우
a = Test("A")
b = Test("B")
c = Test("C")
A - 생성되었습니다
A - 파괴되었습니다
B - 생성되었습니다
B - 파괴되었습니다
C - 생성되었습니다
- 변수에 저장했으면 나중에 활용한다는 의미이므로 프로그램이 종료되는 순간까지 메모리에서 제거되지 않음
프라이빗 변수
- 클래스 내부의 변수를 외부에서 사용하는 것을 막고 싶을 때 사용
- 표현법
- __변수이름
class Person:
def __init__(self, name, age, address):
self.hello = "안녕하세요"
self.name = name
self.age = age
self.address = address
maria = Person("마리아", 20, "서울시 마포구")
print(maria.name)
마리아
class Person:
def __init__(self, name, age, address, wallet):
self.hello = "안녕하세요"
self.name = name
self.age = age
self.address = address
self.__wallet = wallet
maria = Person("마리아", 20, "서울시 마포구", 10000)
print(maria.__wallet) # 클래스 바깥에서 비공개 속성에 접근하면 에러가 발생
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
Cell In[31], line 1
----> 1 print(maria.__wallet)
AttributeError: 'Person' object has no attribute '__wallet'
class Person:
def __init__(self, name, age, address, wallet):
self.hello = "안녕하세요"
self.name = name
self.age = age
self.address = address
self.__wallet = wallet
def pay(self, amount):
self.__wallet -= amount #비공개 속성은 클래스 안의 메서드에서만 접근할 수 있음
print(f"{self.__wallet}원 남음")
maria = Person("마리아", 20, "서울시 마포구", 10000)
maria.pay(3000)
7000원 남음
maria.__wallet -= 3000
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
Cell In[35], line 1
----> 1 maria.__wallet -= 3000
AttributeError: 'Person' object has no attribute '__wallet'
print(maria.hello)
안녕하세요
maria.hello = "안녕하세요!!"
print(maria.hello)
안녕하세요!!
게터(getter), 세터(setter)¶
- 위와 같은 예제에서 프라이빗 변수를 변경하고 싶다면 직접 접근할 수 없기 때문에 간접적인 방법을 사용해야함
- 게터와 세터는 프라이빗 변수의 값을 추출하거나 변경할 목적으로 간접적으로 속성에 접근하도록 해주는 함수
import math
class Circle:
def __init__(self, radius):
self.__radius = radius
def get_circumference(self):
return 2 * math.pi * self.__radius
def get_area(self):
return math.pi * (self.__radius ** 2)
# 게터와 세터를 선언
def get_radius(self):
return self.__radius
def set_radius(self, value):
self.__radius = value
c = Circle(10)
print(c.get_circumference())
print(c.get_area())
print(c.get_radius())
62.83185307179586
314.1592653589793
10
c.set_radius(2)
print(c.get_circumference())
print(c.get_area())
print(c.get_radius())
12.566370614359172
12.566370614359172
2
함수를 사용해 값을 변경하게 하면 여러가지 추가 처리를 할 수 있음
예) 반지름의 값을 양의 숫자로만 한정
import math
class Circle:
def __init__(self, radius):
self.__radius = radius
def get_circumference(self):
return 2 * math.pi * self.__radius
def get_area(self):
return math.pi * (self.__radius ** 2)
# 게터와 세터를 선언
def get_radius(self):
return self.__radius
def set_radius(self, value):
if value <= 0:
raise TypeError("반지름은 양의 숫자여야 합니다")
self.__radius = value
c = Circle(10)
c.set_radius(-2)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[51], line 3
1 c = Circle(10)
----> 3 c.set_radius(-2)
Cell In[50], line 19, in Circle.set_radius(self, value)
17 def set_radius(self, value):
18 if value <= 0:
---> 19 raise TypeError("반지름은 양의 숫자여야 합니다")
20 self.__radius = value
TypeError: 반지름은 양의 숫자여야 합니다
데코레이터를 사용한 게터와 세터
- 게터와 세터를 함수로 만드는 일이 많아져서 게터와 세터를 쉽게 만들 수 있는 기능을 제공
- 표현법
- @property
- @게터함수이름.setter
import math
class Circle:
def __init__(self, radius):
self.__radius = radius
def get_circumference(self):
return 2 * math.pi * self.__radius
def get_area(self):
return math.pi * (self.__radius ** 2)
# 게터와 세터를 선언
@property
def radius(self):
return self.__radius
@radius.setter
def radius(self, value):
if value <= 0:
raise TypeError("반지름은 양의 숫자여야 합니다")
self.__radius = value
c = Circle(10)
print("원래 반지름", c.radius) ##게터함수명으로 프라이빗 변수에 접근
c.radius = 2 ##세터에 들어감
print("변경된 반지름", c.radius)
원래 반지름 10
변경된 반지름 2
c.radius = -10
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[57], line 1
----> 1 c.radius = -10
Cell In[54], line 21, in Circle.radius(self, value)
18 @radius.setter
19 def radius(self, value):
20 if value <= 0:
---> 21 raise TypeError("반지름은 양의 숫자여야 합니다")
22 self.__radius = value
TypeError: 반지름은 양의 숫자여야 합니다
- 데코레이터를 이용하면 객체.변수 를 사용하는 것 만으로 자동으로 게터와 세터가 호출되도록 할 수 있음
상속(inheritance)
- 다른 누군가가 만들어 놓은 기본 형태에 내가 원하는 것만 추가하거나 교체하는 것
- 다중 상속
- 다른 누군가가 만들어 놓은 형태들을 조립해서 내가 원하는 것을 만드는 것
- 기반이 되는 것을 부모(parent)라고 부르고, 이를 기반으로 생성된 것을 자식child)이라고 부름
- 부모가 자식에게 자신의 기반을 물려주는 것이기 때문에 상속이라고 부름
class Person: # 부모 클래스
def __init__(self, name):
self.name =name
def eat(self, food):
print(self.name + "가 " + food + "를 먹습니다")
class Student(Person): #자식클래스
def __init__(self, name, school):
super().__init__(name)
self.school = school
def study(self):
print(self.name + "는 " + self.school + "에서 공부합니다")
potter = Student("해리포터", "호그와트")
potter.eat("감자")
해리포터가 감자를 먹습니다
potter.study()
해리포터는 호그와트에서 공부합니다
# 부모 클래스 선언
class Parent:
def __init__(self):
self.value = "테스트"
print("Parent클래스의 생성자가 호출되었습니다")
def test(self):
print("Parent 클래스의 test() 메서드입니다")
# 자식 클래스의 선언
class Child(Parent):
def __init__(self):
super().__init__() #부모의 생성자 호출
print("Child 클래스의 생성자가 호출되었습니다")
child = Child()
child.test()
print(child.value)
Parent클래스의 생성자가 호출되었습니다
Child 클래스의 생성자가 호출되었습니다
Parent 클래스의 test() 메서드입니다
테스트
자식 클래스의 생성자¶
- 자식 클래스는 부모 클래스가 없으면 존재할 수 없음
- 따라서 자식 클래스의 생성자를 구현할 때는 반드시 부모 클래스의 생성자를 먼저 호출해야함
- 자식 클래스에서 생성자를 생략한다면 부모 클래스의 생성자가 자동으로 호출되기 때문에 super()를 사용하지 않아도 됨
class Person:
def __init__(self):
self.hello = "안녕하세요"
class Student(Person):
pass
james = Student()
print(james.hello)
안녕하세요
자식 클래스의 인스턴스 자료형
- 자식 클래스 객체는 자식 클래스의 객체임과 동시에 부모 클래스의 객체
print(isinstance(james, Student))
print(isinstance(james, Person))
True
True
클래스 상속의 활용
- 부모에 정의되어 있는 함수를 자식에서 다시 정의하는 것을 재정의 또는 오버라이드(override)라고 부름
- 기존 함수/변수 이외의 것을 완전히 새로 정의하는 것도 가능
class Person:
def greeting(self):
print("안녕하세요")
class Student(Person):
def greeting(self):
print("안녕하세요. 인스턴스 메서드 입니다.")
james = Student()
james.greeting()
안녕하세요. 인스턴스 메서드 입니다.
class Student(Person):
def greeting(self):
super().greeting() #부모 클래스의 메서드를 이용하여 중복을 줄임
print("인스턴스 메서드입니다.")
james = Student()
james.greeting()
안녕하세요
인스턴스 메서드입니다.
다중 상속
class Person:
def greeting(self):
print("안녕하세요")
class University:
def manage_credit(self):
print("학점 관리")
class Undergraduate(Person, University):
def study(self):
print("공부하기")
james = Undergraduate()
james.greeting()
james.manage_credit()
james.study()
안녕하세요
학점 관리
공부하기
728x90
'01_Python' 카테고리의 다른 글
47_모듈 (0) | 2025.01.14 |
---|---|
46_Visual Studio Code설치(VS Code) (0) | 2025.01.13 |
44_클래스 (1) | 2025.01.10 |
43_파이썬 내장함수 (0) | 2025.01.09 |
42_데이터 입출력 (1) | 2025.01.09 |