Python의 객체 지향 프로그래밍 이해 및 개념 정리

절차 중심 프로그래밍

절차 중심 접근법은 비즈니스 로직을 상단부터 하단으로 코드를 작성하는 방식입니다!

예시:

요구사항 1: 인증 기능이 필요한 프로그램:

사용자 정보 딕셔너리 정의:
user_data = {
            "zhangsan":"mima1",
            "lisi":"mima2",
            "wangwu":"mima3",
}

로그인 검증 수행:

user_input = input("\033[32;1m사용자 이름을 입력하세요:\033[0m") 
pass_input = input("\033[32;1m비밀번호를 입력하세요:\033[0m")

if user_data.get(user_input):     
    if pass_input == user_data[user_input]: 
        print("\033[32;1m로그인 성공\033[0m")
    else:
        print("\033[31;1m비밀번호 오류\033[0m")
else:
    print("\033[31;1m존재하지 않는 사용자 이름\033[0m")<br></br><br></br>

다른 인증 프로그램이 필요해졌을 때?
코드를 다시 복사해야 합니다!
user_data = {
            "zhangsan":"mima1",
            "lisi":"mima2",
            "wangwu":"mima3",
}

로그인 검증 수행:

user_input = input("\033[32;1m사용자 이름을 입력하세요:\033[0m") 
pass_input = input("\033[32;1m비밀번호를 입력하세요:\033[0m")

if user_data.get(user_input):     
    if pass_input == user_data[user_input]:
        print("\033[32;1m로그인 성공\033[0m")
    else:
        print("\033[31;1m비밀번호 오류\033[0m")
else:
    print("\033[31;1m존재하지 않는 사용자 이름\033[0m") 

N개의 프로그램에서 이 인증 기능을 사용해야 할 경우?
모든 코드를 복사해야 합니다! 하지만 추가 요구사항이 생겼습니다!
로그인 시도 횟수 제한(3회 초과 시 잠금)을 추가해야 하는데, 모든 코드를 수정해야 하나요?

절차 중심 프로그래밍의 단점은 명확히 드러납니다: 호출 시마다 재작성해야 하며 코드가 길고 재사용성이 없으며 새로운 기능 추가 시 전체 코드 수정이 필요합니다!

이 문제를 해결하기 위한 방법은 함수의 등장입니다!!

함수 중심 프로그래밍

함수 중심 접근법은 특정 기능을 함수로 포장하여, 이후 반복적인 작성 없이 단지 함수를 호출할 수 있도록 합니다!

함수 설명: 함수는 기능 블록으로 이해할 수 있습니다. 큰 기능을 작은 블록으로 나누어 원하는 기능을 호출할 때 해당 블록을 사용하면 됩니다! 함수는 레고 조각처럼 생각할 수 있습니다. 여러 조각을 통해 원하는 기능을 조합할 수 있습니다! 함수는 다른 함수를 호출할 수 있으며, 메인 함수는 다른 함수들을 연결하고 호출하는 역할을 합니다! 함수 자체는 호출되지 않으면 실행되지 않습니다!

예시:
동일한 요구사항:
인증 기능이 필요한 프로그램:

user_data = {
            "zhangsan":"mima1",
            "lisi":"mima2",
            "wangwu":"mima3",
}

def authenticate_user(): #함수 정의
    user_input = input("\033[32;1m사용자 이름을 입력하세요:\033[0m") 
    pass_input = input("\033[32;1m비밀번호를 입력하세요:\033[0m")

    if user_data.get(user_input):     
        if pass_input == user_data[user_input]:
            print("\033[32;1m로그인 성공\033[0m")
        else:
            print("\033[31;1m비밀번호 오류\033[0m")
    else:
        print("\033[31;1m존재하지 않는 사용자 이름\033[0m") 
    
authenticate_user() #함수 호출

N개의 프로그램에서 이 모듈을 사용해야 할 경우 매우 간단합니다!
예를 들어 authenticate_user()는 독립적인 파일(모듈)로 구성되어 있습니다:

간단하게 호출할 수 있습니다. 인증이 필요한 경우 단순히 함수를 호출만 하면 됩니다! 새로운 기능 추가 시 함수 내부에만 수정하면 되므로 호출하는 다른 프로그램은 변경 사항을 알지 못합니다.

함수 중심 프로그래밍의 장점: 재사용성이 높고 코드 길이가 짧아지고 확장성이 우수합니다!

요약: 함수는 절차 중심을 한 번 포장하여 고정된 기능을 하나의 컵에 담아두고, 사용할 때는 컵을 가져오면 됩니다. 아래 그림 참조

디코레이터:

디코레이터는 특별한 의미를 가진 함수로, 함수나 클래스를 장식하여 실행 전후에 작업을 추가할 수 있습니다.

간단히 말해 기존 함수를 수정하지 않고 감싸서 처리할 수 있습니다!

새로운 요구사항이 생겼습니다! func1, func2, func3, func4 등 많은 프로그램에 인증을 추가해야 합니다.

#!/usr/bin/env python
#-*- coding:utf-8 -*-

user_data = {
            "zhangsan":"mima1",
            "lisi":"mima2",
            "wangwu":"mima3",
}

def authenticate_user(): #함수 정의
    user_input = input("\033[32;1m사용자 이름을 입력하세요:\033[0m") 
    pass_input = input("\033[32;1m비밀번호를 입력하세요:\033[0m")

    if user_data.get(user_input):     
        if pass_input == user_data[user_input]:
            return True
        else:
            return False
    else:
        return False

def wrapper(func):
    def inner():
        if authenticate_user(): #로그인 성공 시 True 반환 후 func 함수 실행
            func()
        else:
            return "\033[32;1m로그인 실패\033[0m"
    return inner


@wrapper
def func1():
    print("hello This is Func1")
@wrapper
def func2():
    print("hello This is Func2")
@wrapper
def func3():
    print("hello This is Func3")
@wrapper
def func4():
    print("hello This is Func4")

func1()
#func2()
#func3()
#func4()

객체 지향 프로그래밍

이전에 함수의 역할이 재사용과 확장을 용이하게 한다고 했습니다. 사실 객체 지향 없이도 함수만으로 특정 기능을 구현할 수 있습니다!

예를 들어 C 언어는 객체 지향이 없지만 Linux와 같은 대규모 시스템을 개발할 수 있습니다.

그렇다면 왜 객체 지향이 필요한가? 객체 지향은 코드를 더 쉽게 재사용하고 확장할 수 있게 해줍니다!

객체 지향 용어 설명: Object Oriented Programming은 프로그래밍의 설계 방법론입니다.

ps: 객체 지향은 함수를 한 번 더 포장하고 최적화한 것으로 볼 수 있습니다. (필요하다면 이렇게 표현할 수 있습니다)

1. 클래스 & 객체란 무엇인가?

클래스: 템플릿으로 생각할 수 있습니다. 사람들이 "사람"이라는 말을 할 때 누구를 가리키는지는 모르겠습니다!

객체: 실제 물체로, 자신의 속성과 행동을 가지며, 예를 들어 앨렉스와 에릭이 있을 때, 앨렉스는猥琐하고 에릭은闷骚한 특징과 행동이 있음을 알 수 있습니다!

2. 포장 & 인스턴스화 & 호출

예시(1)

프로그래머인 소월월이 함수를 이용해 여자친구 앨렉스를 만들었으나, 앨렉스가 떠난 후 새로운 여자친구 에릭을 만드려고 합니다. 두 여자친구 모두 먹기, 자기 등의 동일한 행동이 있으나, 객체 지향 없이는 코드 재사용이 어려웠습니다. 이것이 객체 지향이 탄생한 이유입니다.

예시(2)

위 예시를 참고하면, 이제 두 함수를 정의하여 여자친구의 행동을 처리할 수 있습니다:

#!/usr/bin/env python
#-*- coding:utf-8 -*-
def sleep(name):
    print("The Girl friend %s is sleeping....." % name)
def eat(name):
    print("The Girl friend %s is eating....." % name)

grilfred1sleep = sleep('alex')
grilfred2sleep = sleep('eric')
grilfred1eat = eat('alex')
grilfrend2eat = eat('eric')

출력 결과:
The Girl friend alex is sleeping.....
The Girl friend eric is sleeping.....
The Girl friend alex is eating.....
The Girl friend eric is eating.....

함수를 호출할 때 매번 이름을 알려주어야 하나요? 파라미터를 전달하지 않으면 누가 호출했는지 알 수 없을 것입니다.

클래스 정의:

#!/usr/bin/env python
#-*- coding:utf-8 -*-

class Person(object):  #클래스 Person(object) 정의, object는 필수 파라미터
    def __init__(self,name):  
        self.name = name      #grilfrend1.name = alex, grilfrend2.name = eric
    def eat(self):
        print("The Girl friend %s is eating...." % self.name)
    def sleep(self):
        print("The Girl friend %s is sleeping...." % self.name)

grilfrend1 = Person('alex')
grilfrend2 = Person('eric')


grilfrend1.eat()
grilfrend2.eat()  #호출 시 이름을 전달할 필요가 없습니다!

결과적으로 클래스를 사용하면 매번 특정 파라미터를 입력할 필요가 없어집니다.

#!/usr/bin/env python
#-*- coding:utf-8 -*-

class Person(object):  
    def __init__(self,name,age):  
        self.name = name      
        self.age = age
    def eat(self):
        print("The Girl friend %s is eating...." % self.name)
    def sleep(self):
        print("The Girl friend %s is sleeping...." % self.name)
    def age_now(self):
        print("%s ,I am %d year old" % (self.name,self.age))

grilfrend1 = Person('alex',18) 
grilfrend2 = Person('alxe',19) 

grilfrend1.eat()
grilfrend1.age_now()  #메서드를 직접 호출할 수 있습니다!

그래서 앞으로 프로그래밍할 때는 특정 사람을 만들어내기보다는 추상화를 하고, 생성할 때 한 번에 여러 개를 생성할 수 있어야 합니다!

정적 메서드:

도구 클래스가 있고, 매번 메서드를 호출할 때 인스턴스화할 필요가 없다면?

class Tools(object):
    @staticmethod  #정적 메서드 설정
    def hatchet():
        print("axe someting.....")
    @staticmethod 
    def saw():
        print("saw someting.....")

Tools.hatchet()  #인스턴스화 없이 호출 가능

private 속성:

class Game(object):
    def __init__(self):
        self.__name = "shuaige"# private 속성
        self.age = 19 # 일반 속성

gamer1 = Game()

print(gamer1.age) # 정상 출력
print(gamer1.__name) # AttributeError 발생

class Game(object):
    def __init__(self):
        self.__name = "shuaige"
        self.age = 19 

gamer1 = Game()

gamer1.__name = 'shuaige'  #private 속성을 접근하는 방법
print(gamer1.__name)

# 상속 관계에서도 private 속성 접근 불가
class Game(object):
    def __init__(self):
        self.__name = "shuaige"
        self.age = 19 

class Newgame(Game):
    def say_name(self):
        print(self.__name)

gamer2 = Newgame()

gamer2.say_name()

# 요약: private 속성은 클래스 내부에서만 접근 가능

상속

소월월과 여자친구가 아이를 낳았고, 아이를 위한 클래스를 만들었습니다. 미래에 많은 자식들이 생길 경우, 자식 클래스와 사람 클래스는 많은 공통점이 있습니다. 예를 들어 먹기, 자기, 나이 등. 이를 다시 작성해야 하나요? Python에서는 상속을 통해 해결할 수 있습니다!

class Person(object):  
    def __init__(self,name,age):
        self.name = name      
        self.age = age
    def eat(self):
        print("The Girl friend %s is eating...." % self.name)
    def sleep(self):
        print("The Girl friend %s is sleeping...." % self.name)
    def age_now(self):
        print("%s ,I am %d year old" % (self.name,self.age))

class Child(Person):
    def cute(self):
        print("TH child %s is very cute" % self.name)

child1 = Child('xiaoxiaoyueyue',2) 

child1.eat()  #Child 클래스에 eat 메서드가 없음에도 부모 클래스의 메서드를 상속받아 사용

추상 클래스와 메서드

from abc import ABCMeta,abstractmethod  

class Car(object):
    def __init__(self,color,brand):
        self.color = color
        self.brand = brand
    def start(self):
        print("staring the car")

class Bmw(Car):  
    def __init__(self,color,brand):
        self.color = color
        self.brand = brand
    def notstart(self):
        print("you cant contrl myself")

car1 = Bmw('rad','bmw')
car1.notstart()

class Car(object):
    def __init__(self,color,brand):
        self.color = color
        self.brand = brand
    @abstractmethod
    def start(self):
        print("staring the car")

class Bmw(Car):  
    def __init__(self,color,brand):
        self.color = color
        self.brand = brand
    def start(self):
        print("BMW starting")

car1 = Bmw('rad','bmw')
car1.start()

요약: 추상 클래스와 메서드는 상위 템플릿에서 메서드를 정의하고 하위 클래스에서 반드시 구현하도록 강제합니다!

태그: python decorator OOP Class Inheritance

7월 16일 17:52에 게시됨