객체 지향 프로그래밍
- 파이썬은 함수형 프로그래밍과 객체 지향 프로그래밍을 모두 지원
- 최근에는 객체 지향 프로그래밍 기법을 많이 이용
특징
- Encapsulation(캡슐화)
- 관련 있는 속성과 메서드를 묶어야 함
- 불필요한 부분은 외부로 노출시키지 않도록 하는 것
- 클래스, 인스턴스, 접근 지정자를 설정하는 부분
- Inheritance(상속)
- 하위 클래스가 상위 클래스의 모든 것을 물려받는 것
- 상위 클래스를 super class 또는 based class 라고 부르고 하위 클래스를 sub class 또는 derived class 라고 부름
- Polymorphism(다형성)
- 동일한 메시지에 대하여 다르게 반응하는 성질
- 동일한 코드가 대입된 인스턴스에 따라서 다른 메서드를 호출하는 것
- 서브클래싱
용어
- Object: 프로그램에서 사용되는 모든 것
- Class: 사용자 정의 자료형, 동일한 목적을 사용하기 위해 모인 데이터(Attribute, Field, 속성)와 기능(Method)의 집합
- Instance: 클래스를 기반으로 만들어진 객체
- Method: 클래스 안에 만들어진 함수
파이썬에서 클래스 선언
class 클래스이름:
초기화 메서드
속성
메서드
인스턴스 생성
클래스이름()
-> 생성자 호출
클래스나 인스턴스를 이용한 멤버 호출
- 클래스이름 이나 인스턴스이름.멤버
class Student:
pass
# 인스턴스 생성
student1 = Student()
메서드 선언
- 파이썬에서 인스턴스가 호출할 수 있는 메서드는 반드시 1개 이상의 매개변수를 가져야 함
- 관습적을 self 라는 이름으로 사용
- 일반적으로 다른 언어에서는 self를 생략하고 실제 클래스가 만들어질 때 this 나 self 또는 me 라는 예약어로 접근이 가능
- 메서드는 클래스 안에 만들어지고 클래스와 인스턴스가 호출할 수 있음, 인스턴스 안에는 메서드가 없음
- 인스턴스는 만들어질 때 자신의 클래스에 대한 참조를 가지고 만들어저서 자신에게 없는 멤버는 클래스에서 찾아옴
- 파이썬에서 인스턴스를 가지고 할당문을 사용하면 인스턴스 내부에 속성이나 메서드를 생성
- 인스턴스가 호출할 때 메서드(인스턴스이름) 형태로 호출해 인스턴스를 self로 참조시킴
class Student:
def display(self):
print("Student 클래스의 인스턴스 메서드")
# 인스턴스 생성
student1 = Student()
student1.display # bound 호출 : 인스턴스가 메서드 호출
Student.display(student1) # unbound 호출 : 클래스가 메서드 호출
메서드 호출
- 클래스 내부에서 호출할 때는
self.메서드이름(첫번째 self에 해당하는 매개변수를 제외하고 매개변수를 대입)
- 바운드 호출(인스턴스가 호출):
인스턴스이름.메서드이름(첫번째 self에 해당하는 매개변수를 제외하고 매개변수를 대입)
- 언바운드 호출(클래스가 호출):
클래스이름.메서드이름(인스턴스, 첫번째 self에 해당하는 매개변수를 제외하고 매개변수를 대입)
속성 생성
- 클래스 안에서 속성을 만들면 클래스의 속성이 만들어짐
- 인스턴스가 속성을 호출하면 자신의 속성이 있으면 자신의 속성을 호출하고 자신의 속성이 없으면 클래스의 속성을 호출
- 속성에 할당을 하면 인스턴스 내부에 자신의 속성이 생성
class Student:
schoolName = "현대 오토에버"
def display(self):
print("Student 클래스의 인스턴스 메서드")
# student1에 schoolName 이라는 속성이 없으므로 클래스에 가서 찾아서 읽음
student1 = Student()
print(student1.schoolName) # 클래스의 속성 호출
# 할당문을 사용하게 되면 인스턴스 내부에 속성을 생성함
student1.schoolName = "현대 모비스" # 할당문 사용, 인스턴스에 할당
print(student1.schoolName) # "현대 모비스" 출력
# 아직 student2에 schoolName 이라는 속성을 만들지 않았으므로 클래스의 schoolName을 호출
student2 = Student()
print(student2.schoolName) # "현대 오토에버" 출력
== 와 is
==
연산자는 __eq__ 메서드를 편리하게 사용하기 위한 연산자- 이 연산자는 연산자 오버로딩이 가능하기 때문에 클래스 별로 다르게 구현되어 있음
- 때로는 가리키고 있는 데이터를 비교하기도 하고 내부 구성 요소들을 비교하기도 함
- id가 같은지 비교하는 연산자는
is
class Student:
schoolName = "현대 오토에버"
def display(self):
print("Student 클래스의 인스턴스 메서드")
li1 = [10, 20]
li2 = [10, 20]
print(id(li1))
print(id(li2))
print(li1==li2) # True 출력
print(li1 is li2) # False 출력
인스턴스 속성을 클래스 내부에서 생성
- 메서드 내부에서
self.속성이름
을 사용하면 인스턴스 속성을 만들거나 사용할 수 있음 - 메서드 외부에서는
self
가 없기 때문에 인스턴스 속성을 만들수가 없음
파이썬에서 명령법
- 일반적인 언어에서는 클래스 이름은 대문자로 시작하고 인스턴스 이름은 소문자로 시작
- 초창기 파이썬에서는 클래스 이름도 소문자로 시작
- 속성이름이나 메서드 이름은 소문자로 시작하고 다른 단어가 나오면 첫글자만 대문자로 하도록 하는 것이 일반적
- 파이썬은 2개 단어 이상의 조합으로 만들 때 두번째 단어의 첫글자를 대문자로 하지 않고 _ 를 앞에 추가하는 경우가 많음
- 정수를 가져오는 메서드 이름을 정한다면 일반적인 언어에서는 getInt 이렇게 하는데 파이썬에서는 get_int 로 명명하는 경우가 많았음
- 연산자 오버로딩이나 특별한 기능을 하는 메서드를 만들 때는 앞에 __ 를 추가하고 뒤에 __ 를 추가하는 형식으로 명명
- readonly 데이터를 만들 때는 모두 대문자로 하는 것이 관례
Accessor - 접근자 메서드
- 인스턴스 속성의 값을 읽고 쓰는 메서드
- 객체 지향 언어에서는 속성의 값을 직접 읽거나 쓰는 것을 권장하지 않음. 대다수의 객체 지향 언어가 상호 배제를 적용할 때 인스턴스나 메서드 단위라서 속성을 접근하게 되면 상호 배제를 적용하기 어려운 경우가 있음
- 속성은 private으로 숨기고 메서드를 public으로 만들어서 접근하기를 권장
- 속성의 값을 리턴하는 메서드 - getter
- 이름은
get속성이름
의 형태로 이름을 만드는 것을 권장하는데 속성의 자료형이 bool인 경우는 get 대신 is를 사용 - 내용은 속성을 리턴하도록 만듬
- 매개변수는 없음
- 이름은
- 속성의 값을 수정하는 메서드 - setter
- 이름은
set속성이름
의 형태로 만듬 - 매개변수 1개를 받음
- 내용은 매개변수의 값을 속성에 대입
- 내용 이외의 것을 작성하는 경우가 있는데 이 경우는 대부분 유효성 검사 문장을 앞에 추가해서 정해진 도메인의 값만 설정하도록 함
- 이름은
class Student:
# 인스턴스 속성을 만들어주는 메서드
def initialize(self):
self.name = None
self.num = 0
# num에 대한 접근자 메서드
def getNum(self):
return self.num
def setNum(self, num):
self.num = num
def getName(self):
return self.name
def setName(self, name):
self.name = name
# 인스턴스를 생성하고 속성을 생성하는 메서드 호출
student = Student()
student.initialize()
student.setName("adam")
student.setNum(1)
print(student.getNum())
print(student.getName())
초기화 메서드:__init__
- 다른 언어에서는 생성자라고 호칭하는 경우가 많음
- 인스턴스를 만들 때 호출되는 메서드
- 메모리 할당과 초기화 작업을 수행
- 클래스를 만들고 __init__ 를 재정의하지 않으면 매개변수가 없는 아무일도 하지 않는 __init__가 자동으로 생성
- 이 메서드는 직접 호출하는 것이 아니고
클래스이름()
으로 호출
class Student:
def __init__(self):
print("초기화메서드")
- 직접 __init__을 생성하는 경우 기존에 제공되는 __init__은 소멸됨
- 매개변수가 있는 __init__을 만들 때는 주의해야 함, 기본값을 제공하는 것이 좋음
- 이 메서드에 정의하는 내용은 매개변수를 받아서 속성에 대입해서 초기화하는 작업
class Student:
# 초기화 메서드 정의
def __init__(self):
self.name = None
self.num = 0
# num에 대한 접근자 메서드
def getNum(self):
return self.num
def setNum(self, num):
self.num = num
# name에 대한 접근자 메서드
def getName(self):
return self.name
def setName(self, name):
self.name = name
# 인스턴스를 생성하고 속성을 생성하는 메서드 호출
student = Student()
print(student.getNum())
print(student.getName())
class Student:
# 초기화 메서드 정의
def __init__(self, num=0, name="adam"):
self.name = name
self.num = num
# def __init__(self, num, name): 으로 값을 줄 수도 있음
# setter 불필요
# 매개변수가 있는 생성자를 만들면 기본적으로 제공되는 생성자가 소멸
# 매개변수를 2개 받은 생성자를 만들었기 때문에 매개변수가 없는 생성자는 없어져서 이 작업은 에러가 됨
# __init__(self) 가 있어야만 아래 문장이 에러가 아님
# 모든 매개변수에 기본값을 설정해 줘야함
# num에 대한 접근자 메서드
def getNum(self):
return self.num
def setNum(self, num):
self.num = num
# name에 대한 접근자 메서드
def getName(self):
return self.name
def setName(self, name):
self.name = name
# 인스턴스를 생성하고 속성을 생성하는 메서드 호출
student = Student()
print(student.getNum())
print(student.getName())
student1 = Student()
인스턴스가 메모리 해제될 때 호출되는 메서드:__del__
- 이 메서드를 인스턴스가 메모리 해제될 때 자동으로 호출되는 메서드
- 매개변수로 self만 가능, 다른 매개변수를 가질 수 없음
- 외부 자원을 사용하는 경우 외부 자원에 대한 연결을 해제하는 코드를 작성
Garbage Collection
- 메모리 해제를 수행해주는 객체
- 파이썬은 reference count(retain count)를 이용해서 메모리를 관리
- 인스턴스가 메모리 할당을 받으면 이 숫자가 1이 되고 이 영역을 다른 데이터가 참조를 하게 되면 1씩 증가함
- 이 참조를 가리키는 변수에 None을 할당하면 이 숫자가 1씩 감소
- reference count가 0이 되면 메모리 해제를 수행할 수 있음
- reference count를 확인하고자 할 때는 sys 모듈을 getrefcount 함수를 이용하면 되는데 이 때는 나오는 값은 1이 증가해서 나오게 됨
- 이 모듈이 인스턴스를 참조했기 때문
class Student:
# 초기화 메서드 정의
def __init__(self, num=0, name="adam"):
self.name = name
self.num = num
# def __init__(self, num, name): 으로 값을 줄 수도 있음
# setter 불필요
# 매개변수가 있는 생성자를 만들면 기본적으로 제공되는 생성자가 소멸
# 매개변수를 2개 받은 생성자를 만들었기 때문에 매개변수가 없는 생성자는 없어져서 이 작업은 에러가 됨
# __init__(self) 가 있어야만 아래 문장이 에러가 아님
# 모든 매개변수에 기본값을 설정해 줘야함
# num에 대한 접근자 메서드
def getNum(self):
return self.num
def setNum(self, num):
self.num = num
# name에 대한 접근자 메서드
def getName(self):
return self.name
def setName(self, name):
self.name = name
# 인스턴스가 메모리에서 해제 대상이 될 때 호출되는 메서드
def __del__(self):
print("소멸자")
student1 = Student() # 인스턴스를 생성하면 인스턴스의 레퍼런스 카운트는 1
student2 = student1 # 인스턴스의 참조를 다른 변수에 대입하면 레퍼런스 카운트는 1증가
# None을 대입하면 레퍼런스 카운트는 1 감소
# 레퍼런스 카운트가 0이 되면 메머리 해제 대상이 되고 접근할 수 없게 됨
student1 = None
print(student2.getNum())
student2 = None
static method
- 클래스 이름으로 호출하는 메서드
- 인스턴스가 없어도 호출 가능
- 인스턴스가 호출해도 됨
- self가 없는 메서드
- 메서드를 만들 때 @staticmethod 라는 데코레이터를 이용해 정의
- 클래스 속성은 사용이 가능하지만 self가 없기 때문에 인스턴스 속성은 사용할 수 없음
class method
- static 메서드처럼 클래스 이름으로 호출하는 메서드
- 첫번째 매개변수로 클래스 객체 자신을 넘겨받아서 사용
- 이름은 관습적으로 cls 라고 함
- @classmethod 라는 데코레이터를 이용해 정의
- 인스턴스가 호출해도 됨
class Student:
@staticmethod
def sMethod():
print("static method")
@classmethod
def cMethod(cls):
print("class method")
Student.sMethod()
Student.cMethod()
student = Student()
# 클래스 메서드나 static 메서드를 인스턴스를 이용해서 호출 가능
# 이런식으로 호출하는 것은 삼가는게 좋음
student.sMethod()
stack: 인스턴스, 호출된함수
heap-instance 영역: 인스턴스는 자신의 클래스 아이디를 참조
-static영역: 상수, 함수, 클래스
-스택 영역의 인스턴스는 자신의 속성만 가짐, 클래스아이디만 참조, 메서드는 클래스에 있음
-인스턴스로 정적/클래스 메서드 호출시 stack->instance영역->static영역으로 찾아가 시간이 걸림
t = T() -> Heap에 T클래스 메모리 할당, instance 영역에 T아이디 참조, stack에서 instance영역 참조
__slots__속성
- 이 속성에 속성 이름을 list로 설정을 하면 인스턴스가 이 속성 이외의 속성을 생성할 수 없음
class Student:
# 이 클래스로 만들어지는 인스턴스는 num과 name 속성만 가져야 함
__slots__ = ["num", "name"]
def __init__(self, num=0, name="noname"):
self.num = num
self.name = name
student = Student()
# 인스턴스에 새로운 속성을 추가
student.age = 30 # 에러
print(student.age)
접근지정자
- 대다수의 객체 지향 언어는 클래스 내부에서만 접근 가능한 것과 클래스 외부에서 인스턴스나 클래스 이름을 이용해서 접근하는 두가지 나누어서 속성이나 메서드 관리
- 객체 지향의 첫 번째 원칙인 캡슐화는 불필요한 부분은 숨기고 필요한 부분만 외부로 공개
- 숨기는 것을 private 으로 설정한다고 하고 외부로 공개하는 것을 public으로 한다고 함
- 파이썬은 기본적으로 모두 public이고 앞에 __를 추가하면 private이 됨
class Student:
def __init__(self, num=0, name="noname"):
# 앞에 __ 를 붙여서 속성 생성하면 인스턴스 외부에서 접근 불가
self.__num = num
self.__name = name
property
- 속성을 이용해서 접근할 때 메서드를 호출하도록 만들어주는 문법
- 대다수의 객체 지향 언어는 속성에 직접 접근을 금지하고 메서드를 호출해서 사용하도록 하는데 이렇게 만들면 속성의 값을 가져오거나 설정할 때 메서드 호출 구문을 작성해야 하는데 이를 간단하게 하기 위해서 속성에 직접 접근하는 것처럼 속성의 값을 가져오거나 설정하는 형태의 기능
- 형식
프로퍼티이름 = property(fget=None, fset=None, fdel=None, doc=None)
프로퍼티 이름
을 호출하면 fget에 설정된 메서드가프로퍼티이름=
하게되면 fset에 설정된 메서드가 호출
class Student:
def __init__(self, num=0, name="noname"):
# 앞에 __ 를 붙여서 속성 생성하면 인스턴스 외부에서 접근 불가
self.__num = num
def getNum(self):
return self.__num
def setNum(self, num):
self.__num = num
num = property(fget=getNum, fset=setNum)
student = Student()
student.num = 1
print(student.num)
- getter 위에
프로퍼티이름.getter 또는 setter
와같이 데코레이터로 가능
class Student:
def __init__(self, num=0, name="noname"):
# 앞에 __ 를 붙여서 속성 생성하면 인스턴스 외부에서 접근 불가
self.__num = num
@property
def getNum(self):
return self.__num
@num.setter
def setNum(self, num):
self.__num = num
student = Student()
student.num = 1
print(student.num)
Operator Overloading
- Method Overloading(중복 정의): 하나의 클래스에 메서드 이름은 같고 매개변수의 개수나 자료형이 다른 형태의 메서드가 존재하는 경우
- Operator Overloading(연산자 오버로딩): 기존 연산자에 새로운 기능을 보여하는 것
- + 의 경우는 숫자 데이터를 더하는 기능을 가지고 있는데 문자열 + 문자열을 하는 경우 숫자 데이터가 아니므로 연산을 수행할 수 없는데 결합하는 기능을 + 문자열 = 결합의 기능을 하도록 만들어 둠
- 연산자 오버로딩을 할 때는 연산자에 해당하는 메서드를 다시 만들면 됨
- +는 __add__, 이메서드는 자기 자신과 다른 하나의 데이터로 매개변수로 받아야 함
class Student:
def __init__(self, num=0, name="noname"):
# 앞에 __ 를 붙여서 속성 생성하면 인스턴스 외부에서 접근 불가
self.__num = num
@property
def getNum(self):
return self.__num
@num.setter
def setNum(self, num):
self.__num = num
# 이 클래스의 인스턴스끼리 더하기를 하면 nu를 더해서 리턴하도록 연산자 오버로딩을 수행
def __add__(self, other):
return self.num + other.num
# print 함수와 같은 출력함수에 인스턴스를 전달했을 때 넘어가는 데이터를 수정
def __str__(self):
return str(self.num)
student1 = Student()
student2 = Student()
student1.num = 1
student2.num = 2
student3 = Student()
student3 = student1 + student2
print(student3.num)
print(student3)
__str__속성
- 거의 모든 프로그래밍 언어는 출력하는 메서드에 인스턴스를 대입해서 출력할 수 있도록 함
- 기본적으로는 인스턴스의 참조를 출력
- 파이썬에서는 __str__(self) 라는 함수를 정의하면 이 함수가 리턴하는 값을 출력
- 대부분의 다른 언어에서는 toString 메서드
__new__(cls, *args, **kwargs)
- 메모리 할당 메서드
- 파이썬에 인스턴스를 생성하면 __new__를 호출해서 메모리 할당(allocation)을 하고 __init__를 호출해서 메모리 초기화를 수행하고 id를 리턴
- Singleton Pattern: 클래스가 인스턴스를 1개만 만드는 디자인 패턴
- 서버에 만드는 클래스들은 대부분 인스턴스를 1개만 만들어서 사용
- 파이썬에서 싱글톤 구현
class Student:
# 리턴할 인스턴스를 저장할 변수
__instance = None
def __new__(cls, *args, **kwargs):
# 인스턴스가 만들어지지 않았다면 인스턴스 생성, 그렇지 않으면 기존 인스턴스 리턴
if cls.__instance is None:
cls.__instance = object.__new__(cls, *args, **kwargs)
return cls.__instance
student1 = Student()
student2 = Student()
print(student1 is student2)
Inheritance
- 하위 클래스가 상위 클래스의 모든 것을 물려받는 것
- 파이썬에서 상속받는 방법
class 클래스이름(상위클래스이름)
class Super:
def greeting(self):
print("안녕하세요")
# Super 클래스로부터 상속받는 하위 클래스
class Sub(Super):
def study(self):
print("공부합시다")
sub = Sub()
sub.study()
# 자신의 클래스에는 메서드가 존재하지 않지만 상위 클래스에 존재해서 사용 가능
sub.greeting()
# 상속 관계인지 확인
print(issubclass(Sub, Super))
- issubclass 라는 함수에 클래스 2개를 대입하면 상속 관계인지 여부를 알려줌
- 첫번째 매개변수로 하위 클래스를 대입하고 두번째 매개변수로 상위 클래스를 대입
- __base__속성을 사용하면 상위 클래스 목록을 확인할 수 있음
- 파이썬은 다중 상속을 지원하기 때문에 상위 클래스가 1개가 아니고 여러 개일 수 있음
- 상위 클래스의 속성을 하위 클래스에서 사용하기 위해서는 __init__메서드를 만들어서 super().init을 호출해야 함
- 여러 클래스로부터 상속 받아서 동일한 메서드가 존재하는 경우 특정 상위 클래스의 메서드를 호출할 때는 super(클래스이름, self). 로 접근
- Method Overriding(재정의): 상위 클래스에 존재하는 메서드를 하위 클래스에서 재정의 하는것
- 목적이 상위 클래스의 메서드 기능 확장
- 오버라이딩을 할 때는 상위 클래스의 메서드를 호출하고 기능을 추가해야 함
- 상위 클래스의 메서드를 호출하지 않을 거라면 오버라이딩을 하지 말고 다른 이름으로 메서드를 만들어야 함
- 안드로이드나 iOS 프레임워크에서 상위 클래스의 메서드를 호출하지 않으면 에러가 발생하기도 함
class Super:
def __init__(self):
self.score = 10
def greeting(self):
print("안녕하세요")
# Super 클래스로부터 상속받는 하위 클래스
class Sub(Super):
# 메서드 오버라이딩 - 상위 클래스에 존재하는 메서드를 하위 클래스에서 다시 정의하는 것
# 목적이 기능 확장
# 파괴할 때를 제외하곤 super()를 앞에 불러야(계란 노른자흰자)
def greeting(self):
super().greeting()
print("반갑습니다")
super().__init__()
# 상위 클래스의 초기화 메서드를 호출해야만 상위 클래스에 만들어진 인스턴스 속성을 사용할 수 있음
def __init__(self):
self.name = "adam"
sub = Sub()
print(sub.name)
print(sub.Score)
sub.greeting()
- 파이썬은 다중 상속을 지원
- 다중 상속: 여러 개의 클래스로부터 상속을 받는 것
- 장점은 여러 클래스들의 멤버를 사용할 수 있음
- 단점은 여러 클래스들의 공통된 이름이 있는 경우 호출이 애매모호해 질 수 있음
- ( ) 안에 여러 클래스 이름을 나열하면 됨
- MRO(Method Resolution Order - 메서드 탐색 순서):
클래스이름.mro()
하면 알 수 있음super()
로 호출하면 첫번째 상위 클래스의 메서드를 호출함super(클래스이름, self)
로 호출하면 다음 상위 클래스의 메서드를 호출
class Super:
def __init__(self):
self.score = 10
def greeting(self):
print("안녕하세요")
# Super 클래스로부터 상속받는 하위 클래스
class Super1:
def greeting(self):
print("Super1")
class Super2:
def greeting(self):
print("Super2")
# Super1과 Super2 클래스로부터 상속받는 하위 클래스
# 여러 개의 클래스로부터 상속을 받으면 앞의 클래스가 메서드 탐색 우선권을 가짐
class Sub(Super1, Super2):
# 메서드 오버라이딩
def greeting(self):
super().greeting()
# Super2의 greeting을 호출하는 방법
# Super1 다음 클래스부터 메서드를 탐색하라고 설정
super(Super1, self).greeting()
sub = Sub()
sub.greeting()
Abstract
- Abstract Method: 내용이 없고 이름만 존재하는 메서드, 하위 클래스에서 반드시 구현해서 사용, Abstract Class 에만 존재해야 함
- Abstract Class: 자신의 인스턴스를 생성할 수 없는 클래스
- abc 모듈을 가져와서 Class의 괄호 안에
metaclass=ABCMeta
를 추가해서 생성 - 추상 메서드를 만들 때
@abstractmethod
를 추가해서 추상 메서드를 생성 - 추상 클래스를 상속받은 클래스는 반드시 추상 메서드를 구현해야 함
- abc 모듈을 가져와서 Class의 괄호 안에
- 구현 이유
- 템플릿 메서드 패턴 구현: 템플릿을 만들고 그 다음 실제 구현
import abc
# 추상 클래스 - 인스턴스를 생성할 수 없음
class Restaurant(metaclass=abc.ABCMeta):
# 추상 메서드: 내용이 없는 메서드
@abc.abstractmethod
def food(self):
pass
# 추상 클래스를 상속받는 클래스
# 추상 클래스를 상속받으면 반드시 추상 메서드를 만들어야 함
class Sub(Restaurant):
def food(self):
print("음식")
sub = Sub()
Delegation
- 존재하지 않는 메서드를 호출하면 에러가 발생
- __getattr__메서드를 구현하면 존재하지 않는 메서드 호출을 에러가 발생하지 않도록 해줌
- 존재하지 않는 메서드를 호출하면 getattr 메서드가 호출됨
coroutine
- cooperative routine을 의미하는데 서로 협력하는 루틴
- 함수가 종료되지 않는 상태에서 다른 함수의 코드를 수행하고 다시 돌아와서 나머지 코드를 수행할 수 있도록 하는 기능
- 일반 함수는 호출을 하면 코드를 한 번에 전체를 실행하지만 coroutine은 코드를 여러 번 실행하는 것이 가능
def tot_coroutine():
tot = 0
# 무한반복
while True:
x = (yield) # 코루틴을 수행하고자 할 때 넘겨주는 데이터를 받기 위한 문장, 여기서 대기
tot = tot + x
print(f"현재까지의 합: {tot}")
co = tot_coroutine()
next(co) # 처음 yield까지 수행
co.send(1) # tot = 1이 되고 print출력 후 다시 yield전에서 멈춤
print("안녕하세요")
co.send(3) # tot = 1 + 3, print후 다시 대기
print("안녕하세요")
co.send(5) # tot = 4 + 5, print후 다시 대기
- coroutine이 외부로 데이터를 전달하고자 할 때는 yield 다음에 데이터를 기재해주면 send와 next의 리턴 값이 됨
def tot_coroutine():
tot = 0
# 무한반복
while True:
x = (yield tot) # 코루틴을 수행하고자 할 때 넘겨주는 데이터를 받기 위한 문장, 여기서 대기
tot = tot + x
print(f"현재까지의 합: {tot}")
co = tot_coroutine()
print(next(co)) # 0 출력
print(co.send(1)) # 1 출력
print("안녕하세요")
print(co.send(3)) # 4 출력
print("안녕하세요")
print(co.send(5)) # 9 출력
- coroutine은 종료되지 않고 대기하도록 무한 반복문을 사용
- coroutine을 강제로 종료하고자 하는 경우에는 coroutine 인스턴스가
close
라는 메서드를 호출하면 됨 - coroutine을 강제로 종료하면 GeneratorExit 라는 예외가 발생
- GeneratorExit 예외를 처리하면 프로그램을 중단하지 않고 계속 수행 가능
def tot_coroutine():
tot = 0
try:
# 무한반복
while True:
x = (yield)
print(x)
except GeneratorExit:
print("코루틴 종료")
# 코루틴 인스턴스 생성 - 함수를 실행하는 것이 아니고 코루틴 인스턴스를 생성하는 것
# 함수 내부에 yield를 가지고 있으면 이 함수는 코루틴
co = tot_coroutine()
next(co)
co.send(100)
# 코루틴 종료
co.close()
print("프로그램 종료")