상세 컨텐츠

본문 제목

[ Python 기초 문법 ] - 클래스(2)

Language/Python

by bing_su 2023. 8. 28. 14:19

본문

반응형
SMALL

앞선 게시물에서는 클래스의 기본 구조에 대해 살펴본 후 사칙연산 클래스를 직접 만들어보며 실습을 진행했다. 이번에는 사칙연산 클래스보다 조금 더 복잡한 클래스를 만들어서 클래스 상속, 연산자 오버로딩에 관한 개념을 살펴볼 예정이다.

[ 실습 -  HousePark and HouseKim 클래스 생성 ]

앞서 만든 사칙연산 클래스보다 조금 더 복잡한 클래스를 만들어보자. 일단 아래의 내용을 토대로 프로그램을 작성해 보고자 한다.

''' 1. 클래스 이름: HousePark, a라는 인스턴스를 만든다. '''
a = HousePark()

''' 2. a.lastname을 출력하면 "박"이라는 성을 출력한다. '''
print(a.lastname)
# 출력 화면
박

''' 3. 이름을 설정하고 a.fullname을 출력하면 이름 전체의 값을 출력한다. '''
a.setname("응용")
print(a.fullname)
# 출력 화면
박응용

''' 4. 여행 가고 싶은 장소를 입력하면 아래와 같이 출력하는 travel 메서드를 만든다. '''
a.travel("부산")
# 출력 화면
박응용, 부산 여행을 가다.

1. 클래스 기능 만들기

먼저, 클래스 이름을 설정하고 a.lastname을 수행하면 "박"을 출력하도록 만들어 보자.

class HousePark:
    lastname = "박"  # 성을 저장하는 클래스 변수

a = HousePark()
print(a.lastname)
# 출력 화면
박

 

위의 예시 코드에서 이름을 설정한 후 print(a.fullname)를 수행하면 이름을 포함한 결괏값이 출력되게 만들어 보자.

class HousePark:
    lastname = "박"
    def setname(self, name):  # 이름 전체를 저장하는 메서드
        self.fullname = self.lastname + name

a = HousePark()
a.setname("응용")
print(a.fullname)  # 이름 전체 출력

# 출력 화면
박응용

 

이제 입력받은 장소로 입력한 사람이 여행을 간다고 출력해 주는 travel 메서드를 구현하자.

class HousePark:
    lastname = "박"
    def setname(self, name):
        self.fullname = self.lastname + name
    def travel(self, where):
        print("{0}, {1}여행을 가다.".format(self.fullname, where))

a = HousePark()
a.setname("응용")
a.travel("부산")

#출력 화면
박응용, 부산여행을 가다.

하지만 구현한 메서드를 아래와 같이 실행하면 오류가 발생한다.

# 실행 코드
a = HousePark()
a.travel("부산")

# Error 화면
Traceback (most recent call last):
  File "c:\Users\judyh\OneDrive\바탕 화면\trash.py", line 9, in <module>
    a.travel("부산")
  File "c:\Users\judyh\OneDrive\바탕 화면\trash.py", line 6, in travel
    print("{0}, {1}여행을 가다.".format(self.fullname, where))
AttributeError: 'HousePark' object has no attribute 'fullname'

해당 오류가 발생하는 이유는 travel 메서드가 self.fullname 변수를 필요로 하기 때문이다. self.fullname 변수는 setname 메서드에 의해 생성되는데 위 실행 코드에서는 setname 함수가 실행되지 않아 오류가 발생하는 것이다.

※ 오류 해결 방법: __init__ 메서드로 초깃값 설정

위에서 만든 HousePark 클래스를 아래와 같이 수정한 후, 해당 코드를 실행하자.

class HousePark:
    lastname = "박"
    def __init__(self, name):  # __init__ 메서드를 사용하여 클래스의 인스턴스 만들 때마다 항상 실행.
        self.fullname = self.lastname + name
    def travel(self, where):
        print("{0}, {1}여행을 가다.".format(self.fullname, where))
a = HousePark("응용")
a.travel("부산")

# 출력 화면
박응용, 부산여행을 가다.

__init__ 메서드에 관한 자세한 설명은 이전 게시물을 참고하자. 이렇게 __init__ 메서드를 이용하여 인스턴스를 생성하는 동시에 초깃값을 줄 수 있다. 이렇게 객체가 생성될 때 자동으로 호출되는 메서드는 생성자(Constructor)가 된다.

2. 클래스 상속(Inheritance)

상속(Inheritance)은 '물려받다.'라는 뜻으로 '재산을 상속받다'라고 할 때의 상속과 같은 의미다. 클래스에도 해당 개념을 적용할 수 있다. 쉽게 설명하면 어떤 클래스를 만들 때 다른 클래스의 기능을 물려받을 수 있게 만드는 것이다. 예시로 이전에 만들었던 HousePark 클래스의 기능을 상속받는 HouseKim 클래스를 구현하고 실행해 보자.

class HousePark:
    lastname = "박"
    def __init__(self, name):
        self.fullname = self.lastname + name
    def travel(self, where):
        print("{0}, {1}여행을 가다.".format(self.fullname, where))

# class Inherited_ClassName (ClassName_to_Inherit) 형식으로 상속
class HouseKim(HousePark):
    lastname = "김"    
juliet = HouseKim("줄리엣")
juliet.travel("독도")

# 출력 화면
김줄리엣, 독도여행을 가다.

위와 같이 HouseKim 클래스는 HousePark 클래스의 모든 기능을 그대로 상속받았기 때문에 따로 __init__과 travel 메서드를 구현하지 않아도 HousePark와 완전 동일하게 동작한다.

juliet = HouseKim("줄리엣")
print(juliet.travel("독도", 3))   # 여행 장소와 기간 모두 출력.

# 출력 화면
김줄리엣, 독도여행 3일 가네.

만약 위와 같이 HousePark 클래스를 상속 받은 HouseKim 클래스에서 travel 메서드를 다르게 동작하도록 하기 위해서는 메서드 오버라이딩(Method Overriding)을 사용해야 한다. 상속한 클래스에 있는 메서드를 동일한 이름으로 다시 만드는 것을 메서드 오버라이딩이라고 한다. 아래 코드를 보며 이해하자.

''' HousePark 클래스 코드는 생략 '''
class HouseKim(HousePark):
    lastname = "김"
    def travel(self, where, day):
        print("{0}, {1}여행 {2}일 가네.".format(self.fullname, where, day))
   
juliet = HouseKim("줄리엣")
juliet.travel("독도", 3)

# 출력 화면
김줄리엣, 독도여행 3일 가네.

위와 같이 travel 메서드를 상속 받은 HouseKim 클래스 안에서 다시 구현했다. (메서드 오버라이딩 사용)

3. 연산자 오버로딩(Overloading)

연산자 오버로딩(Overloading)이란 연산(더하기, 빼기, 곱하기, 나누기)을 객체끼리 수행할 수 있게 하는 기법으로 아래와 같이 동작하도록 만들 수 있다. 

a = HousePark("응용")
juliet = HouseKim("줄리엣")
a + juliet

# 출력 화면
박응용, 김줄리엣 결혼했네.

위와 같이 동작할 수 있도록 하기 위해서는 아래와 같이 이전에 만들었던 클래스들에 몇 가지 사항만 추가하면 된다. 코드를 추가한 후 실행해 보자. 

class HousePark:
    lastname = "박"
    def __init__(self, name):
        self.fullname = self.lastname + name
    def travel(self, where):
        print("{0}, {1}여행을 가다.".format(self.fullname, where))
    def love(self, other):
        print("{0}, {1} 사랑에 빠졌네".format(self.fullname, other.fullname))
    def __add__(self, other):  # 연산자 오버로딩 사용
        print("{0}, {1} 결혼했네.".format(self.fullname, other.fullname))
        
class HouseKim(HousePark):
    lastname = "김"
    def travel(self, where, day):
        print("{0}, {1}여행 {2}일 가네.".format(self.fullname, where, day))
   
a = HousePark("응용")  # a 객체 생성
juliet = HouseKim("줄리엣")  # juliet 객체 생성
a.love(juliet)  # love 메서드 호출
a + juliet

# 출력 화면
박응용, 김줄리엣 사랑에 빠졌네
박응용, 김줄리엣 결혼했네.

연산자에 따라 자동으로 호출되는 메서드를 매직 메서드(Magic Method)라고 한다. __init__, __add__와 같이 언더바가 두 개씩 붙는다는 것이 가장 큰 특징이다.

print(dir(int))를 통해 매직 메서드 확인

지금까지 배운 내용을 토대로 여러 결과를 출력하는 클래스를 작성해 보자.

class HousePark:
    lastname = "박"
    def __init__(self, name):
        self.fullname = self.lastname + name
    def travel(self, where):
        print("{0}, {1}여행을 가다.".format(self.fullname, where))
    def love(self, other):
        print("{0}, {1} 사랑에 빠졌네".format(self.fullname, other.fullname))
    def __add__(self, other):
        print("{0}, {1} 결혼했네.".format(self.fullname, other.fullname))
    def __truediv__(self, other):
        print("{0}, {1} 싸우네.".format(self.fullname, other.fullname))
    def __sub__(self, other):
        print("{0}, {1} 이혼했네.".format(self.fullname, other.fullname))
        
class HouseKim(HousePark):
    lastname = "김"
    def travel(self, where, day):
        print("{0}, {1}여행 {2}일 가네.".format(self.fullname, where, day))
   
a = HousePark("응용")
juliet = HouseKim("줄리엣")
a.travel("부산")
juliet.travel("부산", 3)
a.love(juliet)
a + juliet
a / juliet
a - juliet

# 출력 화면
박응용, 부산여행을 가다.
김줄리엣, 부산여행 3일 가네.
박응용, 김줄리엣 사랑에 빠졌네
박응용, 김줄리엣 결혼했네.
박응용, 김줄리엣 싸우네.
박응용, 김줄리엣 이혼했네.

연산자 오버로딩을 사용하여 여러 메서드를 사용했고, 다양한 결과를 출력할 수 있다. 대표적으로 더하기(__add__), 빼기(__sub__), 나누기(__truediv__), 곱하기(__mul__)을 사용하여 연산자 오버로딩을 사용할 수 있다.

반응형
LIST

관련글 더보기

댓글 영역