Python 혼공노트 5.
- 혼자 공부하는 파이썬(개정판) 청강하며... (그외 파이썬 강의도 …)
보다 나은 프로그램을 만드는 노력:
# 명령형(Imperative) 프로그래밍: 수행할 동작(How)에 중점을 둠
명령문을 사용해서 프로그램이 어떠한 동작을 할 지 순서대로 나열하는 프로그램 작성
# 선언형(Declarative) 프로그래밍: 수행 후 얻을 결과(What)에 중점을 둠
e.g.) html, SQL
# 절차적 프로그래밍
서브루틴, 프로시저, 함수
- 같은 코드를 여러 번 작성하지 말고, 함수를 만들어 사용
- GOTO 구문 또는 JUMP 구문 대신 함수를 사용
# 함수형 프로그래밍
함수는 수학적 개념임에, 순수 함수를 사용
# 객체 지향 프로그래밍
- 변수와 함수를 묶어 하나의 묶음을 통해 규모에 영향을 받지 않는 프로그램을 만들 수 있음
기존 기법/방식으로 작성하며 어려움에 직면함:
- 함수를 많이 사용하다 보니, 함수의 용도 및 존재를 파악하기 어려움 / 영향의 범위를 예측하기 어려움
- 함수를 카테고리로 구분(함수명에 용도를 예측 가능한 키워드를 사용)
> 객체를 중심으로 함수와 변수의 카테고리를 구분하는 단계로 발전
Python:
관심사로 카테고리 구분: 모듈
객채 지향 프로그래밍: 클래스
객체(object) = 속성 + 행위
클래스: 속성과 행위를 통합 (카멜표기법에서 대문자로 시작하는 명명 in Python)
함수(와 변수)를 묶어 놓은 것 / 객체(인스턴스)를 생성하기 위한 설계도
class Class이름:
#Class의 내용
pass
def __init__(self, 매개변수1, 매개변수2 ): # 생성자
self.표현식
self.__매개변수1 = 매개변수1 # “__”로 내가 의도하지 않은 속성의 데이터는 무시 / 외부에서의 접근 제한
self.__매개변수2 = 매개변수2
def __del__(self): # 소멸자
def func(self)
표현식
# 필요시에만 생성: attribute
def get_매개변수1(self):
return self.__매개변수
def set_매개변수1(self, 매개변수1):
return self.__매개변수1 = 매개변수1
# 필요시에만 생성: property
@property
def 매개변수1(self):
return self.__매개변수
@매개변수.setter
def 매개변수1(self, 매개변수1):
return self.__매개변수1 = 매개변수1
인스턴스(객체) = Class이름() # 클래스 호출
1) Class이름.func(인스턴스, 매개변수(s)) # 클래스 내부 함수(메소드) 호출
2) 인스턴스.func(매개변수(s)) # 클래스 내부 함수(메소드) 호출 / 자주 사용되는 방식
클래스(틀): 클래스의 속성을 설명
객체(실체화된 것)": 클래스에 대한 정보를 실제로 정의
실체화한 객체 = "인스턴스" #호출된 클래스
특수한 이름의 함수들: "__"로 시작하는 함수들
def __str__(self): # 전달된 값을 문자열로 반환
return "문자열"
def to_string(self): # 같은 기능의 함수
return "문자열"
def __add__(self, other): # self + other / 기존 내용에 추가
return self
많이 사용되는 약어:
eq: ==, equal
ne: !=, not equal
gt: >, greater than
ge: >=, greater than or equal
lt: <, less than
le: <=, less than or equal
def __eq__(self, other):
return self.속성 == other.속성
def __ne__(self, other):
return self.속성 != other.속성
def __gt__(self, other):
return self.속성 > other.속성
def __ge__(self, other):
return self.속성 >= other.속성
def __lt__(self, other):
return self.속성 < other.속성
def __le__(self, other):
return self.속성 <= other.속성
# 값 객체 / 특정 자료의 단위의 혼동/불일치로 인한 동작/결과 오류를 방지하기 위해 클래스를 활용함
e.g.) in 와 cm의 사용 등…
Class CmLength:
def __ init__(self, cm):
if cm < 0:
raise “length is bigger than ‘0’”
self.__length = cm
def get():
return self.__cm
def __add__(self, other):
if type(other) != CmLength:
raise “use same length”
return CmLength(self.get() + other.get())
CmLength(3) + CmLength(10)
캡슐화 # 객체 사용자가 작성자가 의도하지 않은 동작/사용을 할 수 없도록 함수와 변수를 숨겨 제한하는 것
# 인스턴스 함수와 인스턴수 변수 앞에 “__”를 추가
캡슐화 한 경우, 변수를 직접 제어하는 것은 불가능하나, 별도 함수를 생성하여 가능하도록 할 수 있음
> 잘못된 사용을 예방하기 위한 예외 처리 용으로도 유용함
@property
def get_func(): # getter
표현식
@set_func.setter.
def set_func(): # setter
표현식
프로퍼티 # 캡슐화 한 상태이지만, 문법은 캡슐화하지 않은 상태처럼 동작하도록 할 수 있음
아래 키워드를 함수 위에 삽입하여 프로퍼티임을 명시
@property
@set_func.setter
상속(inheritance): 여러 함수들 중 반복되는 공통된 항목을 묶는 것
- 새로 정의하고자 하는 (자식)클래스가 부모클래스의 기능을 그대로 물려받으면서,
이중 특정 기능을 수정하고자 하거나, 추가적인 기능을 구현하고자 할 때
- 호출된 함수에서 필요한 함수가 없는 경우, 상위 클래스를 찾아 올라가게 됨
- 상속 관계가 복잡할 경우, 코드에 대해 이해가 어려워짐. 상속을 할 경우 위험성이 증가
- 상속 관계일 경우, 부모 클래스가 변하면 자식 클래스에 영향을 줌(함께/계속 수정되어야 함)
class Super_Class: # Parent class)
def __init__(self):
…
class Sub_Class(Super_Class): # Child class
def __init__(self, 매개변수):
…
Super_Class에는 공통된 기능에 대한 빼대/골자를 선언하고, 구체적인 기능은 Sub_Class에서 작성함
e.g.) 상속의 예
class Shape:
def __init__(self):
raise “생성자 구현”
def 넓이(self):
raise “넓이 연산 및 반환 함수 구현”
def 출력보조(self):
raise “출력 보조 함수 구현”
def 출력(self):
print(“=” * 10)
self.출력보조()
print(f”넓이: {self.넓이()}”)
print(“=” * 10)
class Circle(Shape):
def __init__(self, 반지름):
self.파이 = 3.14
self.반지름 = 반지름
def 출력보조(self):
print(f”원의 반지름은 {self.반지름}”)
def 넓이(self):
return self.반지름 * self.반지름 * self.파이
circle = circle(10)
circle.출력()
class Square(Shape):
def __init__(self, 길이):
self.길이 = 길이
def 출력보조(self):
print(f”정사각형 한 변의 길이는 {self.길이}”)
def 넓이(self):
return self.길이 * self.길이
square = Square()
square.출력()
class Triangle:
class Rectangle:
class Ellipse:
…
오버라이드(override): Super_Class에 정의된 함수를 Sub_Class에서 재정의하여, Sub_Class의 기능으로 대체하는 것
class Super_Class:
def function(self):
print(“function of Super_Class”)
class Sub_Class:
def function(self):
print(“function of Sub_Class”
#1 access Super class function
Super_class.function(self)
#2 access Super class function when don’t know which Super_Class / generally use this way
super().function()
child = Sub_Class()
child.function() # call sub class function / generally use this way /
# call Super class function via defined #2 method too.
Sub_Class.fuction(child) # call Super class function via defined #1 method
컴포지션(Composition, Aggregation): 다른 클래스의 일부 메서드를 사용하고 싶지만, 상속은 하고 싶지 않을 경우
- 프레임워크에서 상속을 강제하지 않는 모든 경우에, 컴포지션을 사용
- 상속이나 컴포지션 모두 사용 가능하다면, 대부분의 경우 컴포지션을 사용 가능
- class를 상속받지 않고, 내부에 캡슐화하여 포함(“__” 키워드로 캡슐화)후 활용하는 방식
- class의 속성이 방대/강력한 경우, 의도치 않은 동작 발생 가능성이 급증함에, 해당 기능을 일부러 강제하여 최소화하는 것이 목적
상속: is-a, 암시적 선언 (자식에 없고 부모에 있을 수 있어서 암시)
컴포지션: has-a, 명시적 선언 (자식에 분명하게 명시)
stack : 선입후출(First in Last out, FILO) / 후입선출(Last in First out, LIFO) 구조를 갖는 자료 구조
push: 자료를 입력
pop: 자료를 출력
class Stack:
def __init__(self):
self.__list = []
def push(self, value):
self.__list.append(value)
def pop(self):
output = self.__list[-1]
del self.__list[-1]
return output
stack = Stack()
stack.push(10) # [10]
stack.push(20) # [10, 20]
stack.push(30) # [10, 20, 30]
print(stack.pop()) #30 [10, 20]
print(stack.pop()) #20 [10]
print(stack.pop()) #10
queue: 선입선출(First in First out, FIFO) 구조를 갖는 자료 구조
enqueue: 자료를 입력
dequeue: 자료를 출력
class Stack:
def __init__(self):
self.__list = []
def enqueue(self, value):
self.__list.append(value)
def dequeue(self):
output = self.__list[0]
del self.__list[0]
return output
queue = Queue()
queue.enqueue (10) # [10]
queue.enqueue (20) # [10, 20]
queue.enqueue (30) # [10, 20, 30]
print(queue.dequeue()) #10 [20, 30]
print(queue.dequeue()) #20 [30]
print(queue.dequeue()) #30