Python 이란?
- 1990년 암스테르담의 귀도 반 로섬(Guido Van Rossum)이 개발한 인터프리터(Interpreter) 언어
- 고대 신화에 나오는 파르나소스 산의 동굴에 살던 큰 뱀 (파이썬 표지와 아이콘이 뱀 모양)
- 다양한 라이브러리들과 통합환경의 동시 제공 (numpy, pandas 등)
- 파일 동기화 서비스 드롭박스(Dropbox)
- Web 개발 프레임워크 장고(Django/Flask)
- 머신러닝/딥러닝 라이브러리(Sklearn, tensorflow, mxnet, pytorch..)
Python 특징
- 바이트 코드 컴파일을 지원하는 동적 인터프리팅 언어 (.py > .pyc)
- python shell 에서 interpreter 모드 테스트 가능
- Windows, MAC OS, Palm OS, Android, Unix 계열, Linux 계열 등 다양한 OS 지원
- 컴파일된 외부 모듈을 인터프리터 내부로 동적로딩 지원
- 컴파일 시점이 아닌 프로그램 실행 시점에 Type Checking 을 수행
- 개발생산성 향상 가능
- 디버그 속도 저하 발생 가능
- Runtime 시 객체에 대한 상세 정보 획득 가능
- Object Properties 조작 가능
- 프로그램의 뼈대는 파이썬으로 짜고 빠른 실행속도를 필요로 하는 부분은 C 로 구현하여 import 가능
- Python 의 많은 라이브러리가 C 로 구현됨
- { } (브레이스) 없이 들여쓰기를 통해 단락 구분
- 강제적인 인덴테이션으로 가독성 향상
OOP - Classes and Instances
class Employee:
pass # do nothing
emp_1 = Employee()
emp_2 = Employee() # emp_1, emp2는 클래스(Employee)의 인스턴스, 주소 다름
emp_1.first = "kildong"
emp_1.last = "hong"
emp_1.email = "kildong.hong@gmail.com"
emp_1.pay = 100
print('{} / {}'.format(emp_1.email, emp_1.first))
Class Variables 클래스 변수
- cls 지시자를 통해 access 가능
class Employee:
raise_amount = 1.04
def __init__(self, first, last, pay):
self.first = first
self.last = last
self.pay = pay
self.email = first + '.' + last + '@email.com'
emp_1 = Employee('killdong', 'hong', 10000)
emp_2 = Employee('chunhang', 'sung', 2000)
# raise_amount - 클래스 변수
# first, last, pay, email - 인스턴스 변수
// 클래스 변수 값을 변경하면 해당 인스턴스의 값이 전부 변경된다.
Employee.raise_amount = 1.05
print(emp_1.raise_amount) # 1.05
print(emp_2.raise_amount) # 1.05
print(Employee.raise_amount) # 1.05
// 인스턴스 변수에 대한 값을 변경하면 클래스 변수의 raise_amount 는 바뀌지 않는다.
emp_1.raise_amount = 1.06
print(emp_1.raise_amount) # 1.06
print(emp_2.raise_amount) # 1.05
print(Employee.raise_amount) # 1.05
Static Method and Class Method
- 일반적인 메소드 형태
- parameter 는 self 부터 시작 (instance 의미)
- @classmethod annotation 으로 접근가능
- parameter 는 cls 부터 시작 (class 의미)
- @staticmethod annotation 으로 접근가능
- method parameter 에 self, cls 없음
- util 성 메소드 작성에 적합
- class, instance를 통해서 접근 가능하나 되도록 class 를 통해 호출하는 것이 바람직
class Employee:
raise_amount = 1.04
num_of_emps = 0 ### instance개수를 담을 class variables
def __init__(self, first, last, pay):
self.first = first
self.last = last
self.pay = pay
self.email = first + '.' + last + '@email.com'
Employee.num_of_emps += 1 ## instance개수를 +1씩 증가시킨다.
def fullname(self):
return '{} {}'.format(self.first, self.last)
def apply_raise(self):
self.pay = int(self.pay * self.raise_amount) #Instance Variables는 'self.변수명'으로 접근 가능
# class method선언은 @classmethod annotation을 사용하고
# 메소드 파라미터의 첫인자는 cls를 기본적으로 설정한다.
@classmethod
def set_raise_amt(cls, amount):
cls.raise_amount = amount
@classmethod
def from_string(cls, emp_str):
first, last, pay = emp_str.split('-')
#return Employee(first, last, pay) # __init__ parameter와 같은 순서로 객체를 생성하라.
return cls(first, last, pay)
#static method는 별도의 parameter를 전달하지 않는다.
# weekday()는 '0:월, 1:화, 2:수, 3:목, 4:금, 5:토, 6:일'의 값을 리턴
@staticmethod
def is_workday(day):
if day.weekday() == 5 or day.weekday() == 6:
return False
return True
# class method를 통해서 class variables를 변경한다.
Employee.set_raise_amt(1.05)
# class method를 통한 instance 생성
new_emp_1 = Employee.from_string(emp_str_1)
new_emp_2 = Employee.from_string(emp_str_2)
#static method 호출 > class를 통해 접근
import datetime
my_date = datetime.date(2016, 7, 11)
print(Employee.is_workday(my_date))
# instance를 통해서도 호출은 가능하나, class를 통해서 호출하는 것이 바람직.
new_emp_1.is_workday(datetime.date(2018, 6, 2))
Inheritance-Subclasses
- 부모 클래스의 속성/메소드와 같은 속성/메소드를 자식 클래스에서 재정의 가능
class Employee:
raise_amount = 1.04
def __init__(self, first, last, pay):
self.first = first
self.last = last
self.pay = pay
self.email = first + '.' + last + '@email.com'
def fullname(self):
return '{} {}'.format(self.first, self.last)
def apply_raise(self):
self.pay = int(self.pay * self.raise_amount) #Instance Variables는 'self.변수명'으로 접근 가능
#Employee를 상속하는 자식클래스를 선언
class Developer(Employee):
raise_amount = 1.10
def __init__(self, first, last, pay, prog_lang):
#부모 클래스의 메소드를 실행한다.
super().__init__(first, last, pay)
#Employee.__init__(first, last, pay) #이 코드도 상위 클래스 __init__ call
self.prog_lang = prog_lang
dev_1 = Developer('kildong', 'hong', 10000000) # Java와 달리 new keyword를 사용하지 않음.
dev_2 = Developer('sunghun', 'kim', 5000000) # emp_1(객체)는 클래스(Employee)의 인스턴스(Instance)이다.
#자식클래스가 부모 클래스의 속성과 메소드를 상속하여 정상 동작함.
print(dev_1.email)
print(dev_2.email)
# Employee 를 상속하는 Manager 클래스
class Manager(Employee):
#parameter=None은 해당 parameter가 값이 없을 경우 None으로 설정한다.(default value)
def __init__(self, first, last, pay, employees=None):
#부모 클래스의 메소드를 실행한다.
super().__init__(first, last, pay)
if employees is None:
self.employees = []
else:
self.employees = employees
#부모 클래스에 없는 메소드 정의 가능
def add_emp(self, emp):
if emp not in self.employees:
self.employees.append(emp) #list append
def remove_emp(self, emp):
if emp in self.employees:
self.employees.remove(emp) #list remove
def print_emps(self):
for emp in self.employees:
print('-->{}'.format(emp.fullname()))
Instance Type / Subclass 여부 확인
print(isinstance(mgr_1, Manager)) #True
print(issubclass(Developer, Employee)) #True
print(issubclass(Employee, Manager)) #False
다중상속
- python은 다중상속을 지원하므로 instance 키워드가 없음
class parentA:
def print(self):
print('parentA')
def printA(self):
print('parentA print')
class parentB:
def print(self):
print('parentB')
def printB(self):
print('parentB print')
class Child(parentA, parentB):
def print(self):
super().print()
print('child C')
ins = Child()
ins.print() # 다중 상속 클래스의 선언된 순서에서 우선한 것의 메소드를 실행한다.
ins.printB()
ins.printA()