python 12장. 객체 지향 프로그래밍 (class)

Hyuna·2024년 8월 2일

Python 기본

목록 보기
12/17
post-thumbnail

📌 절차적 프로그래밍의 문제점

  • 코드 재사용의 어려움
  • 유지/보수의 어려움
    : 코드가 길어지고 복잡해질수록 전체 프로그램을 이해하고 수정하기 어렵다
  • 복잡성 관리의 어려움
    : 코드가 여러 파일에 걸쳐 분산되면 전체 시스템 구조를 이해하고 관리하기 어렵다


객체 지향 프로그래밍에서는 위와 같은 문제를 해결할 수 있는 특성을 가지고 있다

📌 객체 지향 프로그래밍의 특성

* 추상화 : 실존하는 사물 or 개념을 컴퓨터에서 처리할 수 있을 정도로 축약해 핵심을 뽑아내는 것
* 캡슐화(은닉성): 필요한 정보와 인터페이스만 공개하고 나머지는 감추는 것
* 재사용성: 클래스 내에 모든 기능을 포함시켜 독립적으로 만들어 다른 클래스에 의존하지 않아도 됨
* 상속: 자식 클래스가 부모 클래스를 상속받으면, 부모 클래스의 모든 속성과 함수들을 포함
* 다형성: 상속 관계의 여러 클래스들에서 동일한 명칭으로 구현된 함수들이 각각 다르게 동작


그렇다면 어떻게 사용되는지 알아보자




1. class

  • 클래스 = 속성(변수) + 기능(함수) + 인터페이스
  • 추상적인 개념으로 실제 메모리에 존재 하지 않음

#이름
SmartPhone

#속성(변수)
owner
number
battery
appList

#기능(함수)
call(phoneNUm)
hwCall(phoneNum)
getBatteryStatus()
  • 클래스 선언

📌 생성자

  • 객체가 생성될 때 호출되어 객체 초기화
  • 생성자는 'init'을 이름으로 가지며, 'self' 를 첫번째 인자로 받는다

📌 인스턴스

  • 클래스의 구체적인 구현체로 메모리에 할당된 실제 객체
  • 클래스의 생성자를 호출하여 생성
  • 인스턴스 변수 이름은 일관적인게 좋다
    ex) self.brand = brand

📌 메서드

  • 클래스의 인스턴스가 수행할 수 있는 동작을 정의
class 클래스_이름:
# 생성자
def __init__(self, 매개_변수_리스트):
    self.객체_변수_이름 = 클래스_매개_변수_리스트 # 인스턴스 변수 정의(초기화)
#메소드
def 이름(self, 매개_변수_리스트):
     코드_블록



class Person:
    def __init__(self, name, age):
        self.name = name  # 인스턴스 변수 name을 초기화
        self.age = age    # 인스턴스 변수 age를 초기화
     
    #메서드 생성 
    def greet(self):
        print(f"Hello, my name is {self.name} and I am {self.age} years old.")

# 인스턴스 생성
person1 = Person("Alice", 30)
person2 = Person("Bob", 25)

# 메서드 호출
person1.greet()  >>  Hello, my name is Alice and I am 30 years old.
person2.greet()  >> Hello, my name is Bob and I am 25 years old.

📍 자동차를 예로 들면 📍
클래스 = 자동차 설계도
생성자 = 엔진,색상,타이어 등을 설정
인스턴스 = 실제 만들어진 자동차
메서드 = 자동차가 할 수 있는 작업 (문을 연다, 창문을 내린다)

💡 Car 클래스를 정의하고, 이 클래스에 make와 model 두 개의 속성을 포함시키세요. 그 후, Car 클래스의 인스턴스를 생성하고, 'Kia'와 'K3'로 초기화한 다음, 이 객체의 make와 model을 출력 해보세요.

class Car:
    def __init__(self, make, model):
        self.make = make
        self.model = model
        
    def car(self):
        print(f"{self.make} {self.model}")
        
result = Car('Kia','K3')

result.car()


📌 상속과 다형성

✔ 다형성: 동일한 함수가 다르게 작동하는 것
✔ 상속

  • 부모 클래스: 기본 클래스, 다른 클래스들이 상속 받을 수 있음
  • 자식 클래스: 부모 클래스를 상속받아 부모 클래스의 속성과 메소드를 사용할 수 있고, 추가적인 속성과 메소드 정의 가능
  • super(): 자식 클래스에서 부모 클래스와 메소드를 호출할 때 사용
super().__init__(make,model) # 부모 클래스의 생성자 호출
super().car() # 부모 클래스의 func() 호출

✔ 오버라이딩(Overriding): 부모 클래스의 소메소드를 자식 클래스에 재정의하며 새로운 동작 구현

  • 부모 클래스의 기존 동작을 유지하면서 추가적인 기능을 구현할 수 있다
class Animal:
    def speak(self):
        return "Some sound"

class Dog(Animal):
    def speak(self):
        return super().speak() + " Woof"

my_dog = Dog()
print(my_dog.speak())  

>> Some sound Woof

  • 메소드 오버라이딩: 같은 이름의 메소드를 자식 클래스에서 다시 정의하는 것

💡 ElectricCar 클래스에서 start 메서드를 오버라이딩하여, "Tesla Model S with a 75kWh battery is starting"와 같이 출력되도록 하세요. 이 메서드를 호출하여 수정된 시작 메시지를 출력하세요.
class Car:
    def __init__(self, make, model):
        self.make = make
        self.model = model
        
    def start(self):
        print(f"{self.make} {self.model} is starting")

class ElectricCar(Car):
    def __init__(self, make, model, battery_size):
        super().__init__(make, model)
        self.battery_size = battery_size
        
    def start(self):
        print(f"{self.make} {self.model} with a {self.battery_size} battery is starting")


my_electric_car = ElectricCar('Tesla', 'Model S', '75kWh')
my_electric_car.start()  



💡 Car 클래스를 상속받는 ElectricCar 클래스를 정의하세요. ElectricCar 클래스는 추가로 batterysize 속성을 가집니다. 이 클래스의 인스턴스를 만들고, 배터리 사이즈를 75kWh로 초기화한 후 모든 정보(make, model, batterysize)를 출력하세요.
출력 예시 "Kia K3 75kWh"

class Car:
    def __init__(self, make, model):
        self.make = make
        self.model = model
        
class ElectricCar(Car):
    def __init__(self, make, model, batterysize):
        super().__init__(make,model)
        self.batterysize = batterysize
        
def my_Car():
    my_car = ElectricCar('Kia','K3','75kWh')
    print(f"{my_car.make} {my_car.model} {my_car.batterysize}")
        

my_Car()





💡 입력 데이터를 기반으로 사각형 또는 원의 면적을 계산하는 프로그램을 작성해보자

>> 요구사항
1) 사각형과 원을 별도의 클래스로 구현, 사각형은 "1" 원은 "0"에 다응
2) 사각형 클래스는 왼쪽 상단(x1,y1)과 오른쪽 하단(x2,y2) 좌표 입력
3) 좌표 값은 정수형
4) 사용자는 모양의 종류를 문자열로 입력하고, 이후 필요한 좌표값이나 반지름을 입력
5) 총 세번의 모양 데이터를 입력받아 각 모양의 면적을 계산하고 출력
import math

class Rectangle:
    def __init__(self, x1, y1, x2, y2):
        self.x1 = x1
        self.y1 = y1
        self.x2 = x2
        self.y2 = y2

    def calcArea(self):
        width = abs(self.x2 - self.x1)
        height = abs(self.y2 - self.y1)
        return width * height

class Circle:
    def __init__(self, x, y, r):
        self.x = x
        self.y = y
        self.r = r

    def calcArea(self):
        return math.pi * (self.r ** 2)

shapeList = []

for i in range(3):
    s = input("도형 모양을 입력하세요 (1:사각형 0:원): ")
    if s == "1":
        x1 = int(input("왼쪽 상단의 x좌표를 입력: "))
        y1 = int(input("왼쪽 상단의 y좌표를 입력: "))
        x2 = int(input("오른쪽 하단의 x좌표를 입력: "))
        y2 = int(input("오른쪽 하단의 y좌표를 입력: "))
        shapeList.append(Rectangle(x1, y1, x2, y2))
    elif s == "0":
        x = int(input("원의 중심 x 좌표를 입력: "))
        y = int(input("원의 중심 y 좌표를 입력: "))
        r = int(input("원의 반지름을 입력: "))
        shapeList.append(Circle(x, y, r))
    else:
        print("유효하지 않은 입력입니다. 0 또는 1을 입력해주세요.")

for s in shapeList:
    print(f"면적: {s.calcArea()}")



💡 위의 코드를 사용자로부터 모양을 문자열로 입력 받은 후, 객체를 먼저 생성하고 객체의 멤버 함수를 이용해 각 모양에 맞는 정보를 입력받게 하자


import math

class Rectangle:
    def __init__(self):
        self.x1 = 0
        self.y1 = 0
        self.x2 = 0
        self.y2 = 0
        
    def input_data(self):
        self.x1 = int(input("왼쪽상단 x 좌표: "))
        self.y1 = int(input("왼쪽상단 y 좌표: ")) 
        self.x2 = int(input("오른쪽하단 x 좌표: ")) 
        self.y2 = int(input("오른쪽하단 y 좌표: ")) 
    
    def calcArea(self):
        width = abs(self.x2 - self.x1)
        height = abs(self.y2 - self.y1)
        return width * height
        
class Circle:
    def __init(self):
        self.x = 0
        self.y = 0
        self.r = 0
        
    def input_data(self):
        self.x = int(input("원 중심 x 좌표: "))
        self.y = int(input("원 중심 y 좌표: "))
        self.r = int(input("원 반지름 길이: "))
    
    def calcArea(self):
        return  math.pi * (self.r ** 2)
    
shapeList = []

for i in range(3):
    s = input("도형 모양을 입력하세요 (1: 사각형 0:원): ")
    if s == '1':
        shape = Rectangle()
    elif s == '0':
        shape = Circle()
    else:
        print("0 또는 1을 입력하세요")
        continue
    
    shape.input_data()
    shapeList.append(shape)
    
for shape in shapeList:
    print(f"도형의 면적: {shape.calcArea()}")


💡 x,y 좌표로 저장할 수 있는 Point클래스를 구현해보자

>> 요구사항
1) x,y좌표를 인자로 전달받아 멤버 변수에 저장하는 init함수를 구현한다
2) Point 클래스 멤버 변수인 x,y를 변경할 수 있는 setX(x), setY(y) 멤버 함수를 구현한다
3) Point 클래스 멤버 변수인 x,y를 각각 반환하는 getX(), getY()를 구현한다

class Point:
    def __init__(self,x, y):
        self.x = x
        self.y = y
    
    def setX(self):
        self.x = int(input("변수 x값 내용을 입력하세요: "))
    
    def setY(self):
        self.y = int(input("변수 y값 내용을 입력하세요: "))
        
    def getX(self):
        return self.x
    def getY(self):
        return self.y
    
point = Point(0,0) #인스턴스 생성

point.setX()   #메서드 호출
point.setY()   

print(f"x값: {point.getX()}")
print(f"y값: {point.getY()}")
    


💡 클래스 Car에서 다음 조건의 매소드를 만들어 보자

1) 초기화 메소드 inint
2) 문자열화 메소드 str
3) 동등 비교 메소드 eq: 객체 모든 값이 동일하면 True, 아니면 False 반환
4) 결과는 자동차 회사: ABC, 년식:2020, 색상: 검정
5) 결과는 자동차 회사: DEF, 년식:2021, 색상: 백색

class Car:
    def __init__(self, company, year, color):
        self.company = company
        self.year = year
        self.color = color
    def __str__(self):
        return f"자동차 회사: {self.company}, 년식: {self.year}, 색상: {self.color}"
    
    def __eq__(self, other):
        if isinstance(other, Car):
            return self.company == other.company and self.year == other.year and self.color == other.color
        return False
        
        
mycar = Car('ABC', 2020, '검정')
yourcar = Car('DEF',2021, '백색')
print(mycar)
print(yourcar)
print(mycar == yourcar)


💡 아래 딕셔너리 자료는 연도별 고등학교의 학급당 학생 수(2021 교육 기본 통계 결과 발표 자료)이다

>> d = {2010:33.7, 2011:33.1, 2012:32.5, 2013:31.9, 2014:30.9, 2015:30.0, 2016:29.3, 2017:28.2, 2018:26.2, 2019:24.5, 2020:23.4, 2021:23}
>> 요구사항
1) 전해에 비해 가장 급격하게 학생수가 줄어든 해는?
2) 학급당 학생수가 30명 미만으로 떨어진 해는?
3) 2010년부터 2021년 사이에 평균적으로 학급당 학생수는 어느 정도 감소했는지?
class Problem:
    def __init__(self,students):
        self.students = students
        
    def subproblem1(self):
        max = 0
        yea = 0
        for i in range(2011,2022):
            if self.students[i-1] - self.students[i] >= max:
                max = self.students[i-1] - self.students[i]
                year = self.students[i]
        print(f"(1) 전해에 비해 가장 급격하게 학생수가 줄어든 해는 {year: .1f}입니다")
    
    def subproblem2(self):
        year = 0
        for i in range(2010,2022):
            if self.students[i] < 30 :
                year = self.students[i]
        print(f"(2)학급당 학생수가 30명 미만으로 떨어진 해는 {year}입니다")
    
    def subproblem3(self):
        sum = 0
        for i in range(2011,2022):
            sum += self.students[i-1]-self.students[i]
        print(f"(3)2010년부터 2021년사이 평균적으로 감소한 학생수는 {sum /11: .2f}입니다")
    
d = {2010:33.7, 2011:33.1, 2012:32.5, 2013:31.9, 2014:30.9, 2015:30.0, 2016:29.3, 2017:28.2, 2018:26.2, 2019:24.5, 2020:23.4, 2021:23}       
result = Problem(d)
result.subproblem1()
result.subproblem2()
result.subproblem3()

0개의 댓글