Object Oriented Programming

Posted by on January 11, 2019

Recently by the same author:


Python에서 Singleton 구현

You may find interesting:


Reentrant Lock


Thread의 lock

Object Oriented Programming

2019. 01. 11 (Fri)
  • 프로그래밍 패러다임
  • 현실에 가깝게(상식적인) 프로그래밍
  • 속성 + 행동
  • 독립된 단위인 객체들의 모임으로 프로그래밍
  • 주로 주어.동사() 로 표현하겠다
  • dir(객체) : 객체가 가진 메서드 출력
    • method : 객체를 조작하는 방법
  • 메서드를 보고 찍어보자


프로그램을 설계할 때 전체 프로그램의 기능을 생각하자



I. 클래스(Class)

객체는 객체를 정의하는 특성을 갖고 있다.

현실의 공통된 부분(특징)추출, 분류하여 설계

공통된 특성을 기준으로 구조화 되어있다.

속성(attribute) 와 메서드(method, 행동)로 이루어짐



(1) 선언 및 정의

class <className>

모든 메서드에 self(객체 스스로) 인자를 두어 속성을 공유하도록 함



(2) 생성자

def __init__(self변수, …) : 생성자 정의

self로 사용하는게 관례적



(3) 메서드

클래스 내부의 모든메서드는 self 인자를 받아야 함

모든 객체가 공통적으로 생성되자 마자 사용할 수 있어야함

self.<value> : 클래스 내부의 속성 호출

__repr()__ : 클래스 자체 정보를 출력. 보통 재정의 해서 사용



(4) 인스턴스

<변수> = <className>() : 인스턴스 생성

예시라는 의미이며, 물체라는 의미로 오브젝트와 같은 의미

공통된 특성을 기준으로 이루어진 클래스를 실제로 구현한 것

isinstance(<인스턴스>, <클래스>) : 클래스의 인스턴스인지 판별



(5) self

특별한 상황을 제외하고, 무조건 메서드에서 self를 첫번째 인자로 설정한다.

메서드는 인스턴스 객체가 함수의 첫번째 인자로 전달되도록 되어있다.

iu.greeting() # == iu.greeting(iu)
  • 인스턴스의 메서드가 호출되면 self에 의해 인스턴스가 자동으로 들어가게 된다.
Person.greeting()
  • 클래스 자체에서 메서드를 호출하므로 self인자가 전달되지 않고 위 코드는 오류가 발생한다.
Person.greeting(iu) # == iu.greeting()
  • 이런 식으로 인스턴스를 전달하여 작동하게 할 수도 있다.

  • 클래스는 그저 이름공간일 뿐




II. 용어 및 개념

class Person:                      #=> 클래스 정의(선언) : 클래스 객체 생성
    name = '홍길동'                  #=> 클래스 변수(데이터 어트리뷰트) : 모든 인스턴스가 공유
										# 클래스 자체가 갖고 있는 정보
        
    def __init__(self, input_name) :
        self.name2 = input_name		# 멤버 변수 : 각각의 객체가 가지는 정보를 넣는다.
    
    def greeting(self):            #=> 멤버 메서드(메서드)
        print(f'{self.name}')

iu = Person()       # 인스턴스 객체 생성
daniel = Person()   # 인스턴스 객체 생성
iu.name             # 데이터 어트리뷰트 호출
iu.greeting()       # 메서드 호출
  • 클래스의 공간과 인스턴스의 공간은 독립적
  • 인스턴스는 클래스의 공간에 접근하려면 Person.을 붙여 접근해야함



(1) 클래스-인스턴스간의 이름공간

클래스를 정의하면, 클래스 객체가 생성되고 해당되는 이름 공간이 생성된다.

인스턴스를 만들게 되면, 인스턴스 객체가 생성되고 해당되는 이름 공간이 생성된다.

인스턴스의 어트리뷰트가 변경되면, 변경된 데이터를 인스턴스 객체 이름 공간에 저장한다.

즉, 인스턴스에서 특정한 어트리뷰트에 접근하게 되면 인스턴스 -> 클래스 순으로 탐색을 한다.

  • 글로벌 변수에는 접근하지 않는다.

자기 자신의 속성은 자신 내부에서만 사용하도록 설계할 것

self : 인스턴스 지칭

Person : 클래스 지칭

클래스 밑에 선언한 변수는 모두 클래스 변수

메서드, 생성자 내부에서 선언한 변수는 인스턴스 변수



(2) 생성자 / 소멸자

del <객체> : 객체 소멸

생성자 : 값을 초기화 하는 과정에서 활용



(3) 정적 메서드 vs 멤버 메서드

정적 메서드 선언

  • 인자값을 받지 않음
  • annotation을 쓰지 않아도 됨

정적 메서드는 클래스의 변수를 조작하지 않는다.

해당하는 클래스가 빈번하게 사용하게 될 함수를 이름 공간 안에 넣기만 한다.

클래스나 인스턴스와 상관 없는 메서드

@staticmethod
    def into() :
        print("I'm human")



클래스 메서드

  • 인자로 클래스를 넘겨받음(보통 cls로 인자 이름을 설정)
  • 클래스를 전달 안해도 알아서 클래스를 넘김
  • 클래스 내부의 값을 조작하는 메서드



(4) 연산자 오버라이딩

기존에 사용되는 연산자를 클래스의 상황에 맞게 바꿔서 사용

  • ex) String concatenation = ‘+’
  • 덮어 쓴다는 개념의 오버라이딩



(5) 상속

클래스명에 부모의 클래스를 인자로 받아서 동작

클래스들의 공통된 속성, 메서드들을 부모 클래스에서 정의하고 상속받아 실행


메소드 실행

  1. 일단 내부 인스턴스에서 메소드 찾음
  2. 없으면 클래스에서 찾음
  3. 없으면 슈퍼 클래스에 올라가서 찾음
  4. 없으면 전역에서 찾음


issubclass(<자식>, <부모>) : 상속관계인지 나타냄

super() : 부모 클래스의 내용을 사용하고자 할 때 사용. 부모 클래스에 접근

부모의 생성자 호출

class Person:
    def __init__(self, name, age, number, email):
        self.name = name
        self.age = age
        self.number = number
        self.email = email 
        
    def greeting(self):
        print(f'안녕, 난 {self.name}')
        
class Student(Person):
    def __init__(self, name, age, number, email, student_id):
        super().__init__(name, age, number, email) # == Person.__init__(...)
        self.student_id = student_id


다중 상속

프로그램이 복잡해지기 때문에 웬만하면 사용하지 않는다.

파이선은 첫번째로 선언된 클래스를 따라간다.

그러고 싶지 않다면 생성자 호출시 클래스를 명시해줘야 함

class A(B, C) :
    def __init__(self) :
        C.__init__()