본문 바로가기

Data_Analysis_Track_33/Python

Python_05(객체지향 프로그래밍)

객체지향프로그래밍 : 기존의 절차지향적인 방식의 프로그램의 대형화, 유지보수 등의 관리 관점에서 어려움을 느끼고 

프로그래밍의 방식을 바꾸었다.
프로그램의 개수가 많아짐 -> 관리가 힘들어지고, 프로그램의 개수를 줄일 수는 없음 -> 프로그램을 나누어서 개발한다.(객체지향)
프로그램의 변수와 함수들 간의 연관성을 고려한다. 순서는 나중에 생각한다.(절차지향과 반대)
서로 연관성이 있는 변수와 함수들을 묶어서 모듈화하는 개발하는 언어들을 객체지향 프로그래밍 언어라고 한다.
모듈(객체) : 변수와 변수를 처리하는 함수를 통틀어 말한다. (객체 함수는 메소드라고 한다,)
쉽게 말해서 비슷한 기능을 하는 변수와 함수끼리 모아서 개발한다는 것이다. -> 유지보수하기 편해진다.
파이썬은 객체지향, 절차지향, 함수지향 모두 지원한다.

Instance(객체) : 연관성 있는 값들과 그 값들을 처리하는 함수(메소드)들을 묶어서 가지고 있는 것(값)
- 속성(Attribute, State) : 객체의 데이터/상태로 객체를 구성하는 값들
- 메소드(method, operater, behavior) : 객체가 제공하는 기능으로 주로 Attribute들을 처리한다.

Class(클래스) 정의
Class : 객체의 설계도, 객체의 타입
- 동일한 형태의 객체들이 가져야 하는 Attribute와 Method들을 정의한 것(클래스를 정의할 때 어떤 속성과 메소드를 가지는지 먼저 설계)
- 클래스로 부터 객체(instance)를 생성한 뒤 사용한다.
구문 : 
class 클래스이름:  #선언부
    #클래스 구현
    #메소드들을 정의
클래스 이름의 관례: 파스칼 표기법-각 단어의 첫글자는 대문자 나머진 소문자로 정의한다. ex) Person, Student, HighSchoolStudent

클래스로부터 객체(Instance) 생성
변수 = 클래스이름()
pass -> 일단 클래스명만 정하고 싶다면 pass 선언

class Person:
    pass

# instance : 값, class : Data Type
Person() # instance 생성
p = Person() # 생성한 인스턴스를 변수에 대입

print(type(p))
type(p)

print(type(30), type(30.9), type("aaa"), type(bool), type([1,2])) # Python에서는 모든 값이 객체(인스턴스)다.


Attribute(속성)
attribute는 객체의 데이터, 객체가 가지는 값, 객체의 상태를 의미한다.

객체에 속성을 추가, 조회
- 객체의 속성 추가(값 변경)
1. Initializer(생성자)를 통한 추가 -> 초기화(대부분의 추가 방식은 이 방식을 쓴다)
2. 객체.속성명 = 값 (추가/변경) (추가에 이 방식을 쓰는 것은 좋지 않다. 가능한 변경에 이 방식을 써야한다.)
3. 메소드를 통한 추가/변경
1(Initializer)은 초기화할 때. 2, 3은 속성값을 변경할 때 적용.

- 속성 값 조회
구문 : 객체.속성명 (x.y -> x내부의 y를 뜻한다.)

- 객체.__dict__ -> 객체가 가지고 있는 Attribute들을 dictionary로 반환한다.

p = Person() # 객체 생성 및 변수에 할당
print(p.__dict__) # 객체가 가지고 있는 속성들을 조회
# 속성값들을 추가
p.name = '홍길동'
p.age = 30
p.address = '서울'
p.tall = 182.3


print(p.__dict__)

 

# 속성값들을 조회
print(p.name)
print(p.age)
print(p.address, p.tall)
f"{p.name}은 {p.age}세이고 {p.address}에 살고 있습니다."

 

p2 = Person() # Person instance를  생성해서 p2에 대입
print(p2.__dict__)
p2.name = '유재석'
p2.age = 40
p2.address = "인천"
p2.email = 'abc.com'
print(p2.__dict__)

 

print(p2.age, p2.name, p2.address, p2.email)
print(p2.tall) # 존재하지 않는 값 조회시 AttributeError 발생

 

print(p.name, p2.name) # 두 사람의 정보가 있다.
print(p.__dict__)
print(p2.__dict__)

생성자(Initializer) : 객체를 생성할 때 호출되는 특수메소드로 Attribute들 초기화에 하는 코드를 구현
Inializer를 이용해 초기화하는 Attribute들이 그 클래스의 객체들이 가져야 하는 공통 Attribute가 된다.
구문
def __init__(self [,매개변수들 선언]):  #[ ] 옵션. 관례적으로 매개변수를 self라 칭한다. 디폴트가 있는 파라미터, 

가변인자 모두 가능하다.
    # 구현 -> attribute(instance변수) 초기화
    self.속성명 = 값

self parameter : 메소드는 반드시 한개 이상의 parameter를 선언해야 하고 그 첫번째 parameter를 말한다.

(객체의 위치 -> 주소를 의미한다.)
메소드 호출시 그 메소드를 소유한 instance가 self parameter에 할당된다.
즉, 변수 = 클래스(변수1, 변수2) 여기서 변수1과 변수2는 두번째 parameter부터 차례로 할당된다.
self의 역할은 객체.클래스를 통해 객체를 생성하면 그 객체의 메모리 공간을 의미한다.(객체를 받는다.)
객체 생성 -> 메모리 공간 확보 -> init 메소드 호출-> 생성된 객체를 반환.

# initializer를 이용해서 attribute(객체 변수)를 초기화

class Person:
    
    # initializer
    def __init__(self, name, age, address= None): # 관례적으로 매개변수를 self라 칭한다. 디폴트가 있는 파라미터, 가변인자 모두 가능하다.
        """
        파라미터로 name, age, address를 받아서(객체가 생성되는 시점)
        그 값들을 attribute로 저장
        """
        # 메소드에서 attribute 조회. -> self.변수명 = 값 (대입), self.변수명 (조회)
        self.name = name
        self.age = age # self.age -> age 속성, age : parameter 변수
        self.address = address 
        self.email = None

 

# 객체 생성 : class이름(변수1에 대입할 값, 변수2에 대입할 값) -> __init__(변수1, 변수2) 호출
p = Person("박명수", 33, "부산") # name으로 박명수, age로 33, address로 부산이 들어간다. address에 값이 들어가지 않았다면 None
print(p.__dict__)
p.tall = 180    # 문법적으로 가능하지만 좋은 방식이 아니다. attribute 초기화는 init을 이용해서 하는 것을 지향한다.
                # 객체 생성 후 객체 변수 = 값 은 기존 attribute의 값을 변경할 때 이용한다.
print(p.__dict__)

 

p2 = Person('유재석', 22, '서울')
print(p2.__dict__)


Instance 메소드(method) : 객체가 제공하는 기능, 객체의 attribute 값을 처리하는 기능을 주로 한다.
구문
def 이름(self [, 매개변수들 선언]):
    # 구현
    # attribute 사용(조회/대입)
    self.attribute 
메소드 호출 구문 : 객체.메소드이름([argument, ...])

class Person:
    
    def __init__(self, name, age, address = None):
        self.name = name
        self.age = age
        self.address = address
        self.email = None
    # 메소드 추가
    def print_info(self): # argument를 안받는 메소드
        # person의 attribute값들을 출력
        print(f"이름 : {self.name}, 나이 : {self.age}, 주소 : {self.address}, email : {self.email}")
        
    def add_age(self, age): # parameter는 2개지만, 실질적인 argument는 1개인 메소드
        # 나이를 받아서 attribute age에 더한다.
        self.age += age

 

p1 = Person('유재석', 20, '서울')
p1.print_info()

 

p1.add_age(3)
p1.print_info()

 

p1.email = 'a@a.com'
p1.print_info()

 

class String:
    
    def __init__(self, value):
        self.value = value
        
    def split(self):
        print(f"{self.value}를 분리합니다.")
    
    def upper(self):
        print(f"{self.value}를 대문자로 변경합니다.")
        return self.value.upper()

 

s = String('a b cd') # 변수 s를 클래스 String에 'a b cd'라는 문자열로 선언한다.
s.split() # String 클래스의 split()함수를 실행

 

v = s.upper() # 변수 v를 변수s('a b cd').함수 upper()로 선언한다.
print(v)