본문 바로가기
Python

Python 객체지향 프로그래밍

by FraisGout 2020. 7. 2.

클래스(Class)

클래스와 객체는 길가에서 파는 붕어빵으로 간단히 비유하여 이해할 수 있습니다.

 

프로그래머 관점에서는 붕어빵을 찍어낼 수 있는 틀을 클래스(class)라고 이해할 수 있으며, 붕어빵 틀에서 찍혀 나온 붕어빵 하나하나를 객체(object)라고 이해할 수 있습니다.

 

 

 

이처럼 클래스(class)란 무언가를 계속 똑같이 찍어낼 수 있는 설계도와도 같은 것을 의미합니다.

 

또한 객체(object)란 설계도, 즉 클래스를 바탕으로 찍어낸 제품과도 같은 것을 의미합니다.

 

 

 

다음의 예제에서 클래스와 객체를 구분해봅시다.

 

)

1. 영희 / 사람

2. 영철 / 학생

3. 파이썬 / 프로그래밍 언어

4. *콜라 1.5L 페트병 / 음료

5. 1997년에 생산된 500/ 동전

6. 베이지 천 소파 / 소파

7. 검은 가죽 소파 / 소파

 

 

 

위의 예제에서 왼쪽은 객체로 볼 수 있고 오른쪽은 클래스로 볼 수 있습니다.

 

오른쪽을 기준으로 서로 다른 객체들이 존재하는 것을 확인할 수 있습니다.

 

소파라는 틀 안에서 베이지색 천으로 만들어진 소파와 검은색 가죽으로 만들어진 소파가 나올 수 있습니다. 하지만 그들은 여전히 소파라는 틀을 공유합니다.

 

 

 

여러분은 이제 절차지향프로그래밍을 벗어나 객체지향프로그래밍의 세계에 들어왔습니다.

 

클래스 구성

클래스는 크게 두 가지로 구성됩니다.

 

 

 

1. 속성

 

2. 동작

 

 

 

속성은 클래스가 가지는 변수들을 의미합니다.

 

예를 들어 은행 계좌에는 잔액, 계좌의 주인, 이자율 등이 있을 수 있습니다.

 

 

 

동작은 클래스가 할 수 있는 동작들을 의미합니다.

 

은행 계좌에서 우리는 출금, 입금, 계좌 폐쇄 등을 할 수 있습니다.

 

 

 

사람으로 예를 들자면 속성에는 이름, 나이, 성별, 주소지 등이 들어갈 수 있고, 동작에는 앉기, 일어서기, 걷기, 운동하기 등이 들어갈 수 있는 것입니다.

 

 

 

이처럼 세상에 이미 존재하거나 우리가 만들 무언가에 대해 속성과 동작을 분리해서 분석해보는 습관을 들이면 이후에 클래스를 디자인하는데 훨씬 쉽게 접근할 수 있습니다.

 

그리고 이런 사고방식으로 프로그래밍을 설계하는 것을 객체 지향 프로그래밍(Object Oriented Programming)이라고 합니다.

 

객체(Object)

하나의 클래스로부터 여러 개의 객체(object)가 생성될 수는 있지만 각각은 서로 유일(unique)합니다.

 

서로 다른 객체는 특별히 선언한 문장이 없으면 서로 완전히 독립적입니다.

 

, 내가 한 객체의 A라는 속성값을 변경하여도 다른 객체의 A 속성값은 변하지 않습니다.

 

 

 

객체 지향의 개념

 

 

 

1. Abstraction(추상화) - 만들고자 하는 것들의 공통적인 것을 바탕으로 하나로 묶는 것

2. Encapsulation(캡슐화) - 맡은 역할의 수행을 위해 최소한의 외부 접근만을 허용하는 것

3. Polymorphism(다형성) - 자료형에 구애 받지 않고 프로그래밍 하는 것

4. Inheritance(상속) - 하위 개념이 상위 개념의 속성 및 동작 등을 물려받는 것

 

 

더 자세한 내용은 약간 어려운 내용이므로 구글 등에서 객체지향 프로그래밍이나 OOP로 검색하여 알아보길 바랍니다.

 

 

클래스 선언

파이썬에서 클래스를 선언하는 방법은 다음과 같습니다.

 

클래스 선언

class Horse:

 

 

 

클래스는 class 키워드와 함께 만들고자 하는 클래스의 이름을 나열하여 선언합니다.

 

파이썬에서 클래스의 이름은 일반적으로 대문자로 시작합니다.

 

생성자(Constructor) 선언

생성자 선언

class Horse:

 

def __init__(self, age, height, color, xpos, ypos):

 

self.age = age

 

self.height = height

 

self.color = color

 

self.xposition = xpos

 

self.yposition = ypos

 

self.velocity = 0

 

 

 

우리가 horse 클래스라는 설계도를 얻었다고 가정합시다.

 

이 설계도를 바탕으로 세상에 실제 Horse가 태어나게 해주는 것이 바로 생성자(constructor)입니다.

 

 

 

파이썬에서 생성자의 이름은 항상 __init__으로 고정되며, 다른 이름으로 변경할 수 없습니다.

 

또한, 생성자의 첫번째 매개변수는 반드시 self로 선언해야 합니다.

 

클래스 외부에서 해당 함수를 호출한 객체를 찾는 일은 객체의 이름만 알면 쉽게 찾을 수 있습니다.

 

하지만 클래스 내부에서 호출한 객체를 찾으려면 마땅한 방법이 없습니다.

 

 

 

그래서 도입된 것이 바로 self 키워드입니다.

 

파이썬에서 self 키워드는 해당 함수를 호출한 객체를 가리킵니다.

 

 

 

C++과는 다르게 파이썬은 클래스 내부 변수를 미리 선언하지 않고 사용합니다.

 

아래의 두 코드는 정확히 같은 동작을 하는 코드입니다.

 

C++

class Person{

 

int age;

 

public :

 

Person(){

 

this->age = 17;

 

}

 

}

 

Python

 

class Person:

 

def __init__(self):

 

self.__age = 17

 

private 키워드

private 키워드는 클래스 외부에서 클래스 내부의 멤버에 접근하지 못하도록 하는 키워드로 JAVAC++에서 사용합니다.

 

하지만 파이썬에서는 private 키워드를 사용하지 않고, 변수 앞에 언더스코어(_) 두 개를 붙여서 표현합니다.

 

private 키워드로 설정된 내부 멤버에는 해당 객체 내에서만 접근할 수 있습니다.

 

같은 클래스에서 생성된 객체라더라도 서로 다른 객체의 private 멤버에는 접근할 수 없습니다.

 

public 키워드

public 키워드는 private 키워드와는 반대되는 개념으로 클래스 내부나 외부든 어디에서나 접근할 수 있는 멤버들을 의미합니다.

 

파이썬에서는 private 키워드와 마찬가지로 public 키워드를 사용하지 않고, 변수의 앞과 뒤에 언더스코어(_) 두 개를 붙여서 표현합니다.

 

대표적인 예가 앞서 살펴본 생성자입니다. (__init__)

 

인스턴스화

클래스에 생성자를 만들었다면 이제 실제로 사용해봅시다.

 

)

if __name__ == '__main__':

 

danbi = Horse(5, 160, 'brown', 0, 0)

 

 

 

클래스에서는 생성자를 호출하여 객체를 만드는데 이러한 과정을 인스턴스화라고 합니다.

 

이때 생성자 이름인 __init__을 호출하는 것이 아닌 클래스 이름을 호출하여 객체를 생성하게 됩니다.

 

그리고 생성자의 매개변수 목록과 실제 전달 인수를 순서까지 잘 맞춰 전달해 주어야 합니다.

 

클래스 변수

앞서 같은 클래스에서 생성된 객체라도 서로 완전히 독립적이라고 했습니다.

 

하지만 이러한 객체끼리 정보를 공유하는 방법이 완전히 없는 것은 아닙니다.

 

 

 

바로 클래스 변수라는 것을 사용하면 같은 클래스에서 생성된 객체들끼리 정보를 공유할 수 있습니다.

 

 

 

다음 예제는 Alphabets라는 클래스에서 6개의 객체를 생성하여 python이라는 문자열을 출력하는 예제입니다.

 

)

class Alphabets:

 

__str = ""

 

def __init__(self, text):

 

self.text = text

 

Alphabets.__str += text

 

def print_class_variable(self):

 

print (Alphabets.__str)

 

 

 

if __name__ == '__main__':

 

o1 = Alphabets('p')

 

o2 = Alphabets('y')

 

o3 = Alphabets('t')

 

o4 = Alphabets('h')

 

o5 = Alphabets('o')

 

o6 = Alphabets('n')

 

 

 

o1.print_class_variable()

 

o5.print_class_variable()

 

실행 결과

python

 

python

 

 

 

위의 예제에서 객체 o1o5가 같은 메소드인 print_class_variable() 함수를 호출하고 있으나 그 실행 결과가 같은 것을 확인할 수 있습니다.

 

이것은 6개의 객체가 생성되는 과정에서 Alphabets 클래스의 클래스 변수인 str이 서로 공유되기 때문입니다.

 

따라서 실행된 결과가 순서대로 문자 'p', 'y', 't', 'h', 'o', 'n'이 연결되어 ‘python’이라는 문자열을 출력하게 됩니다.

 

상속(Inheritance)

, , 고양이, 닭 등의 공통점이 무엇일까요? 바로 동물이라는 점입니다.

 

, , , 고양이, 닭 등은 서로 다른 종이지만 동물이라는 공통점을 가지고 있는 것입니다.

 

이것을 프로그래밍 관점에서 살펴보면 말, , 고양이, 닭 등은 모두 동물이라는 공통점을 상속받았다고 이해할 수 있는 것입니다.

 

부모 클래스(superclass)와 자식 클래스(subclass)

자식은 부모의 형질을 유전적인 방법을 통해 물려받습니다.

 

앞서 살펴본 동물은 부모 클래스가 되고 말, , 고양이, 닭 등은 동물 클래스의 자식 클래스가 되는 것입니다.

 

)

import math

 

 

 

class Animal:

 

def __init__(self, age, height, color, xpos, ypos):

 

self.age = age

 

self.height = height

 

self.color = color

 

self.xposition = xpos

 

self.yposition = ypos

 

self.velocity = 0

 

 

 

def sound(self):

 

pass

 

 

 

class Horse(Animal):

 

def __init__(self, age, height, color, xpos, ypos):

 

Animal.__init__(self, age, height, color, xpos, ypos)

 

 

 

def sound(self):

 

print('Neigh')

 

 

 

def run(self, xdistance, ydistance, time):

 

self.xposition += xdistance

 

self.yposition += ydistance

 

total_distance = math.sqrt((xdistance + xdistance) * (ydistance + ydistance))

 

self.velocity = total_distance/time

 

 

 

class Dog(Animal):

 

def __init__(self, age, height, color, xpos, ypos):

 

Animal.__init__(self, age, height, color, xpos, ypos)

 

 

 

def sound(self):

 

print('Bow-Wow')

 

 

 

if __name__ == '__main__':

 

danbi = Horse(5, 160, 'brown', 0, 0)

 

choco = Dog(10, 100, 'black', 50, 30)

 

danbi.sound()

 

choco.sound()

 

실행 결과

Neigh

 

Bow-Wow

 

 

 

위의 예제에서는 Animal이라는 이름의 클래스를 정의하면서 생성자를 정의합니다.

 

그 후에 Animal 클래스를 상속받은 Horse 클래스나 Dog 클래스를 정의할 때는 생성자를 따로 정의할 필요없이 부모 클래스의 생성자를 불러오면 됩니다.

 

이때 만약 자식 클래스가 다른 특성들을 더 가지게 하고 싶다면 부모 클래스의 생성자를 호출한 뒤 특성을 추가하면 됩니다.

 

오버라이딩(Overriding)

오버라이딩(Overriding)이란 부모 클래스로부터 상속받은 특성을 자식 클래스에서 재정의하는 것을 의미합니다.

 

위의 예제에서 자식 클래스의 생성자는 부모 클래스의 생성자를 오버라이딩하여 작성된 것입니다.

 

동적바인딩(Dynamic Binding)

앞서 살펴본 예제의 실행 결과는 다음과 같습니다.

 

)

if __name__ == '__main__':

 

danbi = Horse(5, 160, 'brown', 0, 0)

 

choco = Dog(10, 100, 'black', 50, 30)

 

danbi.sound()

 

choco.sound()

 

실행 결과

Neigh

 

Bow-Wow

 

 

 

위의 예제에서는 두 개의 객체를 생성하고, 각각의 객체에서 sound() 함수를 호출합니다.

 

이때 실행 결과는 danbi 객체의 경우에는 말 울음소리(Neigh), choco 객체의 경우에는 강아지 울음소리(Bow-Wow)가 출력됩니다.

 

 

 

sound() 함수는 Horse 클래스에 존재하고 Dog 클래스에 존재하며 Animal 클래스에도 존재합니다.

 

따라서 sound() 함수를 호출할 때 어떤 클래스에 존재하는 sound() 함수를 호출해야 할지를 결정해야 합니다.

 

이처럼 프로그램의 실행 시간(runtime)에 그 성격이 결정되는 것을 동적 바인딩(Dynamic Binding)이라고 합니다.

 

다중 상속(Multiplex Inheritance)

다중 상속이란 여러 개의 부모 클래스로부터 동시에 특성을 물려받는 것을 의미합니다.

 

C++이나 JAVA 등 일반적인 프로그래밍 언어에서는 보통 다중상속을 허용하지 않고 있습니다.

 

 

 

하지만 파이썬에서는 이러한 다중 상속을 허용하며, 자식 클래스를 생성할 때 클래스명 뒤 괄호 안에 특성을 물려받고 싶은 부모 클래스들을 콤마(,)를 사용하여 나열하면 됩니다.

 

)

class WolfDog(Wolf, Dog):

 

모듈과 패키지

파이썬에서 모듈(module)이란 하나의 파이썬 파일(.py 파일)을 의미합니다.

 

또한 패키지(package)란 이러한 모듈들이 여러 개 모여있는 것을 가리킵니다.

 

여러 개의 파이썬 파일이 폴더에 따라 나뉘어 있는 하나의 큰 폴더를 생각하면 이해하기가 쉬울 것입니다.

 

 

 

파이썬이 지금처럼 많은 사용자들을 보유할 수 있었던 이유가 바로 모듈과 패키지 때문입니다.

 

다른 사람들이 만든 코드를 간단하게 사용할 수 있으며, 배포 또한 손쉽기 때문에 단시간에 크게 성장할 수 있었습니다.

 

모듈 사용법 1

파이썬에서 모듈을 사용하기 위해서는 우선 import 문을 사용하여 해당 모듈을 import 해야만 합니다.

 

이때 import 하고자 하는 모듈의 확장자는 제외하고 파일의 이름만을 import 키워드 뒤에 나열합니다.

 

)

import classNmodule

 

 

 

hihi = classNmodule.Horse(5,160,'brown',0,10)

 

bow = classNmodule.Dog(5,100,'brown',10,10)

 

 

 

hihi.sound()

 

bow.sound()

 

실행 결과

Neigh

 

Bow-Wow

 

 

 

위의 예제는 classNmodule이라는 이름의 파이썬 파일을 import 하여 사용하는 예제입니다.

 

이처럼 모듈을 import 문을 사용하여 가져오게 되면 모듈의 모든 내용이 작성 중인 코드상에 그대로 옮겨진다고 생각하면 됩니다.

 

 

 

코드에서 모듈에 저장된 변수나 함수를 사용하려면 import 한 모듈의 이름을 적은 후 온점(.)을 찍고 나서 사용하고자 하는 변수나 함수의 이름을 적으면 됩니다.

 

모듈 사용법 2

)

from classNmodule import *

 

 

 

hihi = Horse(5,160,'brown',0,10)

 

bow = Dog(5,100,'brown',10,10)

 

 

 

hihi.sound()

 

bow.sound()

 

실행 결과

Neigh

 

Bow-Wow

 

 

 

만약 모듈에 저장된 내용을 자주 사용해서 모듈의 이름이 너무 반복적으로 나올 경우에는 다음과 같이 사용할 수도 있습니다.

 

)

from 모듈이름 import 함수명(클래스명)

 

 

 

위와 같은 문장을 이용하면 코드에서 필요한 함수만을 골라서 import 할 수 있는데, 이때 함수명 대신에 별표(*)를 사용하면 해당 모듈의 모든 함수들을 import 하겠다는 의미가 됩니다.

프로그래밍에서 별표(*)는 보통 모든 것(everything)을 의미합니다.

 

)

from classNmodule import Horse

 

 

 

hihi = Horse(5,160,'brown',0,10)

 

bow = Dog(5,100,'brown',10,10)

 

 

 

hihi.sound()

 

bow.sound()

 

 

 

위의 예제와 같이 Horse 클래스만 import 하면 Dog 클래스는 import 되지 않았기 때문에 인터프리터가 Dog 클래스의 생성자를 찾을 수 없습니다.

 

따라서 bow 객체가 생성되지 못하므로 bow.sound() 함수의 실행 또한 불가능합니다.

 

math 모듈

파이썬의 math 모듈에는 수학과 관련된 다양한 함수들과 상수들이 미리 정의되어 있습니다.

 

이것을 사용하면 여러 수학적인 문제들을 파이썬 프로그래밍을 통해 손쉽게 해결할 수 있습니다.

 

math 모듈은 파이썬에서 기본적으로 제공하는 기본 모듈이므로, 별도의 설치과정 없이 import 만으로 바로 사용할 수 있습니다.

 

 

 

사용 방법

import math

 

또는

 

from math import *

 

 

 

다음과 같은 수학 문제를 파이썬의 math 모듈을 사용하여 풀어보도록 합니다.

 

 

 

1. 원주율 PI값과 오일러 수 e 값을 확인하자.

2. 중심이 (0,0)이고 반지름이 5인 원의 넓이와 θ=60˚일 때의 xy값을 구하자.

 

 

코딩연습

import math

 

 

 

print(math.pi)

 

print(math.e)

 

 

 

radius = 5.0

 

area = (radius ** 2) * math.pi

 

theta = math.radians(60)

 

 

 

x = radius * math.cos(theta)

 

y = radius * math.sin(theta)

 

 

 

print("area : " + str(area))

 

print("x : " + str(x))

 

print("y : " + str(y))

 

실행 결과

3.141592653589793

2.718281828459045

area : 78.53981633974483

x : 2.5000000000000004

y : 4.330127018922193

 

 

 

위에서 주어진 문제들은 고등학교 수학에서 흔히 접할 수 있는 문제들입니다.

 

math 모듈을 사용하면 이러한 수학 문제들을 손쉽게 파이썬으로 풀 수 있습니다.

 

 

1. math 모듈 안에는 pie가 미리 정의되어 있습니다.

 

만약 pi3.14로 놓고 싶다면 math.pi = 3.14 처럼 pi의 값을 변경할 수도 있습니다.

 

2. 원의 넓이는 반지름 * 반지름 * PI값으로 구할 수 있습니다.

 

따라서 math.pi를 이용하면 원의 넓이를 구할 수 있습니다.

 

이때 math 모듈에서 미리 정의된 삼각 함수에는 각도로 라디언(radian) 값을 전달해야만 합니다.

 

따라서 θ=60˚ 이라 할 때 cos(60) 으로 작성하는 것이 아니라 60˚ 에 해당하는 radian 값을 전달해줘야만 합니다.

 

파이썬에서는 math.radians() 함수를 통해 손쉽게 라디언 값을 생성할 수 있게 해줍니다.

3. 원 위의 한 점을 (x,y) 라고 할 때 x = radius * cos θ 로 나타낼 수 있습니다.

4. 변수 area, x, y 의 값은 모두 실수형이므로 문자열과 바로 더하기 연산(+)이 불가능합니다.

 

따라서 입력된 내용을 문자열로 바꿔주는 str() 함수를 사용해야 합니다.

 

turtle 모듈

turtle 모듈은 파이썬에서 기본적으로 제공하는 기본 모듈로 코드에 따라 그림을 그려주는 모듈입니다.

 

math 모듈과 마찬가지로 turtle 모듈도 기본 모듈이므로, 별도의 설치과정 없이 import 만으로 바로 사용할 수 있습니다.

 

 

 

사용 방법

import turtle

 

또는

 

from turtle import *

 

 

 

다음 예제는 turtle 모듈을 사용하여 간단한 사각형을 그리는 예제입니다.

 

)

from turtle import *

 

 

 

forward(100)

 

right(90)

 

forward(100)

 

right(90)

 

forward(100)

 

right(90)

 

forward(100)

 

 

 

mainloop()

 

다음 예제는 turtle 모듈을 사용하여 기하학적인 그림을 그리는 예제입니다.

 

)

from turtle import *

 

 

 

for i in range (20):

 

forward(100)

 

right(90)

 

forward(100)

 

right(90)

 

forward(100)

 

right(90)

 

forward(100)

 

right(72)

 

 

 

mainloop()

 

이처럼 turtle 모듈을 사용하면 코드에 따라 멋진 기하학적인 그림도 출력할 수 있습니다.

 

만약 그림이 생성되고 나서 바로 창이 닫혀서 확인하기가 힘들다면 코드의 맨 마지막에 mainloop() 를 추가하면 창이 닫히지 않습니다.

'Python' 카테고리의 다른 글

Python 함수  (0) 2020.07.02
Python 제어문  (0) 2020.07.02
Python 자료형  (0) 2020.07.02
Python 특징  (0) 2020.07.02

댓글