Class
: 클래스란 관련된 '속성'과 '동작'을 하나의 범주로 묶어 실세계의 사물을 흉내낸 것
- 객체지향의 가장 기본적인 개념이 클래스
- 스크립트 언어는 원래 가볍게 쓰는 것이 주목적이라 객체지향을 지원하는 경우가 드물지만 파이썬은 스크립트 언어임에도 클래스 정의, 연산자 오버로딩, 다중상속을 지원한다. (하지만 진짜 객체지향언어에 비해 형식성이 떨이지고 기능도 많이 부족)
- 사물을 분석하여 필요한 속성과 동작을 추출 -> 모델링
- 모델링된 결과를 클래스로 포장하는 것 -> 캡슐화
- 아래 코드예제는 계좌라는 실세계의 사물(Object)를 표현하는 하나의 묶음 : 연관된 정보는 한 곳에 모여있어야 관리가 용이
balance = 8000 # 잔액
def deposit(money): # 입출금 동작
global balance
balance += money
def inquire():
print("잔액은 %d " % balance)
deposit(1000)
inquire() # 잔액은 9000
- 클래스로 정의
class Account: #Account 클래스 정의, 필요한 동작의 함수 구현
def __init__(self, balance): # 잔액 속성
self.balance = balance
def deposit(self, money): # 입금
self.balance += money
def inquie(self): # 조회
print('잔액은 %d' % self.balance)
obj = Account(8000)
obj.deposit(1000)
obj.inquire() # 잔액은 9000
* 필요한 속성과 동작이 Account클래스로 캡슐화 됨 (클래스는 재사용 가능)
* 모든 것이 클래스 안에 포함되어 있으므로 Account클래스로부터 얼마든지 계좌 생성 가능
* 각 계좌 객체는 속성인 'balance'가 각자 따로 가지며, 'deposit', 'inquire' 메소드는 공유됨
* 기억장소가 분리되어 있어 고유의 값을 저장 가능
클래스 선언 & 생성자
class 이름:
def __init__(self, 초기값):
멤버변수 초기화
메소드 정의
* 클래스 이름은 첫자를 대문자로 하는 것이 관행
* 클래스 선언문 안에 필요한 속성 변수와 동작 메소드를 나열함
* 첫번째 메소드는 객체를 초기화해주는 __init__ 생성자
* __init__의 첫 번째 인수인 self는 객체 자기자신을 의미하여 파이썬 인터프리터가 객체 생성시 자동으로 넣어줌
class Human:
def __init__(self, age, name):
self.age = age
self.name = name
def intro(self):
print(str(self.age) + '세' + self.name + '입니다.')
kim = Human(23, '홍길동') # 객체 생성
kim.intro() # 23세 홍길동입니다.
* 객체를 생성한 후 객체를 생성자(__init__)의 첫번째 인수인 self로 전달
* 생성자는 객체 생성 직후에 호출되어 멤버 변수를 초기화하는 중요한 역할
상속
: 상속은 기존 클래스를 확장하여 멤버를 추가하거나 동작을 변경하는 방법
class 이름(부모):
....
* 비슷한 클래스가 있다면 처음부터 다시 만들필요 없이 Base class를 상속받아 약간씩 확장 및 변형하여 사용
* 상속할 때는 클래스 이름 다음 괄호 안에 부모클래스의 이름을 지정
* 새로 정의되는 자식클래스는 부모클래스의 모든 멤버를 물려받음
* 물려받은 후에 추가로 멤버변수를 더 정의하거나 동작을 수정 가능
class Student(Human): # Human 상속받음
def __init__(self, age, name, stunum):
super().__init__(age, name) # age,name의 초기화는 부모클래스의 초기화와 똑같으므로
self.stunum = stunum # 멤버를 추가로 선언
def intro(self): # 정의하지 않아도 부모메소드 사용가능(but 학번출력X)
super().intro()
print("학번 : " + str(self.stunum))
def study(self): # 메서드 추가로 정의
print("파이썬공부중")
* super() : 부모클래스의 object 리턴
* 한 클래스로부터 상속되는 자식클래스의 개수와 깊이에 제한없음 (Human으로부터 Student, Teacher 등 많은 클래스 파생가능)
* 파이썬은 다중상속(여러개의 부모클래스를 가지는 것)도 가능하지만 프로그램을 복잡하게 만드므로 가급적 사용안하는 것이 좋음
액세서
: 객체의 안정성을 확보하기 위해 정보 은폐 기능으로써 별도로 멤버에 access하는 방법
* Java/c++ 같은 객체지향언어에 비해 파이썬은 공식적으로 정보 은폐를 지원하지 않음
* 따라서 파이썬 클래스의 멤버는 모두 공개되어 있어 외부에서 누구나 액세스 할 수 있음
* 클래스의 멤버를 외부에서 마음대로 조작하게 내버려 두는 것은 위험하므로 일정한 규칙으로 안전하게 액세스해야 함
방법 1) Getter, Setter정의
class Date:
def __init__(self, month):
self.month = month
def getmonth(self):
return self.month
def setmonth(self, month):
if 1 <= month <= 12: # 1 ~ 12 사이의 유효한 값만 받아들이고 그 외는 무시
self.month = month
today = Date(11)
today.setmonth(15) # 이상한 호출
print(today.getmonth()) # 11 (객체가 이상한 값을 가지지 않음)
방법 2) property(getter, setter) 형식으로 속성 정의
class Date:
def __init__(self, month):
self.s_month = month # 실제멤버는 밖에서 알기 어려운 이름으로 정의
def getmonth(self):
return self.s_month
def setmonth(self, month):
if 1 <= month <= 12:
self.s_month = month
# month property를 통해 내부 멤버를 액세스하는 getter, setter와 연결
month = property(getmonth, setmonth)
today = Date(11)
today.setmonth(15)
print(today.getmonth()) # 11
방법 3) 데코레이터로 property 정의
class Date:
def __init__(self, month):
self.s_month = month
# getter는 @property
@property
def month(self):
return self.s_month
# setter는 @이름.setter
@month.setter
def month(self, month): # 함수이름은 위와 동일
if 1 <= month <= 12:
self.s_month = month
today = Date(11)
today.month = 15
print(today.month) #11
방법3) __로 시작하는 멤버변수 이름
class Date:
def __init__(self, month):
self.__month = month # 숨겨진 멤버의 이름을 __로 시작하면 바로 참조가 불가능
def getmonth(self):
return self.__month
def setmonth(self, month):
if 1 <= month <= 12:
self.__month = month
month = property(getmonth, setmonth)
today = Date(10)
today.__month = 7 # 직접 대입으로 변경되지 않는다
print(today.month)
* __가 붙으면 내부적인 실제이름은 '__클래스명__멤버명' 이 됨
ex) '__month' 로 쓰면 실제 이름은 '_Date__month' 가 된다
* 사용자가 숨겨진 이름을 알아내 실수로 대입할 위험을 막을 수 있음
* 물론 이 숨겨진 이름도 직접 대입하면 변경은 가능하나 의도치 않은 실수는 막을 수 있음
-> 너무 복잡한 방법까지 쓸 필요는 없고 getter, setter정도만 잘 작성해도 어느 정도 안전!
클래스 메서드
: 특정 객체에 대한 작업을 처리하는 것이 아니라 클래스 전체가 공유
* 일반적인 메소드는 객체에 소속되는 인스턴스 메소드 (첫번째 인수 self가 해당 객체에 대한 작업 수행)
* 클래스 메소드는 클래스 자체를 나타내는 cls 인수를 받아들임
* 함수 앞에 '@classmethod' 데코레이터를 붙이고 첫번째 인수로 cls 인수 작성
class Car:
count = 0 # Car클래스 소속변수: 특정 객체에 소속되지 않고 모든 객체가 공유
def __init__(self, name):
self.name = name
Car.count += 1 # 차 생성시마다 1씩 증가
@classmethod
def outcount(cls): # 클래스 전체의 공유 값인 count를 출력
print(cls.count)
ferrari = Car("페라리")
lamborghini = Car("람보르기니")
Car.outcount() # 2
* 클래스 멤버는 모든 객체에 의해 공유되므로 각 객체에서도 참조 가능, 그러나 가독성위해 클레스 메소드는 위처럼 작성 권장
ex) print(ferrari.count) 해도 같은 결과
연산자 메소드
: 클래스에 연산자 메소드를 정의하면 객체에 대해서도 연산자를 사용 가능
* 클래스 별로 연산자의 동작을 고유하게 정의하는 기능을 연산자 오버로딩이라고 함
* 피연산자의 타입에 따라 적절한 동작을 정의해 두면 객체를 수식에 바로 활용가능해 편리
* 연산자는 기호로 되어있어 함수의 이름으로 쓸 수 없음 -> 연산자 별로 메소드 이름이 정해져 있음
연산자 | 메소드 | 우변일 때의 메소드 |
== | __eq__ | |
!= | __ne__ | |
< | __It__ | |
> | __gt__ | |
<= | __le__ | |
>= | __ge__ | |
+ | __add__ | __radd__ |
- | __sub__ | __rsub__ |
* | __mul__ | __rmul__ |
/ | __div__ | __rdiv__ |
* 보통 객체가 좌변에 오지만 우변에 올 때는 앞에 r이 붙은 함수명을 사용
* 교환법칙이 성립하는 연산자는 우변일 때의 연산자 메소드가 필요없음
- 예시
class Human:
def __init__(self, age, name):
self.age = age
self.name = name
def __eq__(self, other): # 두 객체가 같은지 비교. 비교 내용은 클래스별로 다름
return self.age == other.age and self.name == other.name
hong = Human(23, "홍길동")
dong = Human(23, "홍길동")
lee = Human(22, "이몽룡")
print(hong == dong) # True
print(hong == lee) # False
* 연산자는 함수에 비해 호출구문이 간단하고 의미가 분명해 사용하기 쉬움
* 사람끼리 더하거나 곱하는 것도 가능하지만 논리적으로 합당한 의미가 있어야 함
특수 메소드
: 특정한 구문에 객체가 사용될 때 미리 약속된 작업을 수행. 메소드를 정의해두면 필요할때 자동으로 호출되어 원하는 작업 수행
메소드 | 설명 |
__str__ | str(객체) 형식으로 객체를 문자열화한다 |
__repr__ | repr(객체) 형식으로 객체의 표현식을 만든다 |
__len__ | len(객체) 형식으로 객체의 길이를 조사한다 |
- 예시
class Human:
def __init__(self, age, name):
self.age = age
self.name = name
def __str__(self):
return "이름 : %s, 나이 : %s" % (self.name, self.age)
hong = Human(23, "홍길동")
print(hong) # 이름 : 홍길동, 나이 : 23
Module
: 모듈은 파이썬 코드를 저장하는 기본 단위
* 해석기는 실행 중인 모든 변수의 값을 저장하고 변화를 추적하지만 해석기를 재시작하면 변수,함수의 정의가 사라짐
* 이 때문에 명령행보다 파일 형태로 작성하여 일괄 실행하는 스크립트(소스 코드)를 사용
* 그러나 스크립트도 너무 길면 편집이 귀찮고 공동작업이 힘드므로 기능 별로 여러개의 파일로 나누어 작성
* 이때 나누어진 스크립트 파일 하나를 모듈 이라고 함
* 파이썬은 자주 사용하는 기능을 표준 모듈로 제공 (standard library)
* 자주 사용하는 기능을 모듈화해두면 중복작업을 방지하고 재사용하기 편리
* 모듈을 import하여 마치 자기가 정의한 것처럼 사용가능
import util # 같은 디렉토리에 있는 util 모듈을 불러옴
# 변수나 함수를 참조할 때는 모듈명을 앞에 붙여 호출
print("1inch = ", util.INCH)
print("~ 10 = ", util.calcsum(10))
Package
: 모듈을 관리하기 위한 상위 개념
* 대규모의 프로젝트 수행 시 모듈의 수가 많아지고 관리에 어려움이 따름
* 그래서 모듈을 관리하기 위한 상위의 패키지라는 개념이 필요
* 모듈이 파이썬 코드를 담는 파일이라면, 패키지는 모듈을 담는 디렉토리
* 디렉토리로 계층을 구성해 놓으면 모듈을 기능에 따라, 개발 주체에 따라 체계적으로 관리할 수 있고 이름 충돌도 피할 수 있음
외부모듈 설치
pip 명령 패키지명
명령 | 설명 |
install | 패키지를 설치한다 |
uninstall | 설치한 패키지를 삭제한다 |
freeze | 설치한 패키지의 목록을 보여준다 |
show | 패키지의 정보를 보여준다 |
search | pyPI에서 패키지를 검색한다 |
'Study > Python' 카테고리의 다른 글
[Python #7] Multiple Connections, Web Scrapping (0) | 2021.12.14 |
---|---|
[Python #6] Network (0) | 2021.11.24 |
[Python #5] Dictionary, Set, Collection (0) | 2021.10.10 |
[Python #4] File (0) | 2021.10.07 |
[Python #3] String, List & Tuple (0) | 2021.10.05 |