본문 바로가기
국비 교육/파이썬

[파이썬] Class (상속, 은닉)

by 육츠 2023. 12. 28.
Contents 접기

특징

- 멤버가 있으나 자바와는 다르게 멤버 변수는 전부  public 이다.
    멤버변수 종류: 접근 한정자 public, private, protected
    __ 2개는 private / _ 1개는 protected 임

class 클래스명:
	pass # 빈클래스
   
someone = 클래스명()

 

Python 생성자

두 개의 생성자를 가질 수 없음.

- 생성자 작성 방법

__init__() 은 클래스당 한 개만 작성 가능.
self : 클래스 내부에서 __init__() 함수의 첫 매개변수여야 함 (self 명칭을 쓰는 것이 관행임)
         self 변수는 객체를 받는 용도이며 생략 불가.

def __init__(self) : # 기본 생성자

def __init__(self, a, b) # 전달인자 두 개 받는 생성자

 

기본생성자

기본생성자(__init()__)는 자동으로 만들어줌.

# class의 이름은 대문자로 시작(암묵적 규칙)

class FourCal:
    # self : 생성된 자기 자신의 객체 참조값을 받기 위한 매개변수
    def setData(self, first, second):
        self.first = first 
        self.second = second
        # 멤버변수 () = 매개변수로 전달된()

# 클래스 생성 시 명시적인 생성자를 만들어 주지 않으면 
# 기본생성자(__init()__)는 자동으로 만들어준다.
# 생성자의 역할은 객체 생성시 멤버 변수를 초기화 해주는 역할을 한다.

a = FourCal() 
# FourCal () 클래스 객체 생성 ,FourCal()은 생성자로서 FourCal() 클래스의 __init()__ (기본 생성자) 을 호출한다.

a.setData(3,4)
print(a.first,a.second)

b = FourCal()
b.setData(5,6)
print(b.first,b.second)
3 4
5 6

 

명시적 생성자

# 명시적 생성자 가지는
# 계좌 객체 생성
# 속성: 계좌주 이름, 계좌 번호, 잔고
#행동방식: 잔고 조회, 입금, 출금, 계좌 정보 조회

class Account:
    # Account 클래스의 속성을 특정 값으로 초기화하기 위한 생성자 필요
    def __init__(self, owner, accNo, balance):
        # 명시적 생성자
        self.__owner = owner 
        # 꼭 owner일 필요 없다. 은닉을 위해 외부에서 유추가 불가능한 멤버 변수를 선언
        self.__accNo = accNo
        self.__balance = balance
    
    # Account 객체가 가지고 있는 잔고 값을 조회하는 함수
    def getBalance(self): # 매개변수가 없어도 self 써야함
        return self.__balance

    # 입금 처리 함수
    def deposit(self,amount):
        self.__balance += amount

    # 출금 처리 함수
    def withdraw(self,amount):
        self.__balance -= amount

    # 계좌 정보 조회 함수
    def accountInfo(self):
        return f"계좌번호: {self.__accNo}, 소유주: {self.__owner}, 잔고: {self.__balance}원"

a1 = Account("홍길동","11-11",500) # 초기값 삽입
a1.deposit(400)
print(a1.accountInfo())

a2 = Account("임꺽정","11-12",300)
print(a2.accountInfo())
계좌번호: 11-11, 소유주: 홍길동, 잔고: 900원
계좌번호: 11-12, 소유주: 임꺽정, 잔고: 300원

 

상속

기본 형식

class 자식클래스명(부모클래스명) :

 

super() : 부모 클래스의 생성자 호출

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def intro(self):
        print(f"저는 {self.age}살 {self.name}입니다.")


kim = Person("홍길동",29)
kim.intro()

lee = Person("이철수", 22)
lee.intro()
저는 29살 홍길동입니다.
저는 22살 이철수입니다.

 

super().__init__(name,age) # 부모클래스(Person) 생성자 호출

class Student(Person):
    def __init__ (self,name,age,stdNo):
        super().__init__(name,age) # 부모클래스(Person) 생성자 호출
        self.stdNo = stdNo

    def study(self): 
        print("Studt Hard")

    def intro(self):
        super().intro()
        print(f"학번은 {self.stdNo}입니다")
# 메서드 재정의: 상속관계에서 부모에 정의된 메서드를 자식 클래스의 상황에 맞게 재정의 하는 것

park = Student("박찬호",30,'2023')
park.intro() # 상속을 통해 사용했다.
저는 30살 박찬호입니다.
학번은 2023입니다

 

매서드 재정의

매서드 재정의 예시

# 메서드 재정의 예시 

class MyDate:
    def __init__(self,year,month,day):
        self.year = year
        self.month = month
        self.day = day
    
# 원하는 형식을 출력하기 위해 __str__() 을 재정의
    def __str__(self):
        return f"{self.year} - {self.month} - {self.day}"

    
d = MyDate(2023,10,25)
print(d)

# print(d.__str__()) 따로 지정해두지 않으면 이 문장을 생략하고 있는 것
# 최상위 슈퍼 클래스에서 상속 받은 것

# 원형을 유지한채 바디만 재정립
2023 - 10 - 25

 

은닉(Encapsulation)

파이썬에서는 private 개념이 없으나 멤버 이름을 감춘 것 같은 효과를 줄 수 있음.
property 를 이용하면 특정값을 읽거나 할당할 때 항상 특정 메서드가 실행될 수 있도록 강제 할 수 있다.

class MyDate:
    def __init__(self,month):
        # 가급적 멤버변수의 이름을 어렵게 설정
        self.__inner_month = month

    def getMonth(self):
        print("getMonth() call")
        return self.__inner_month

    def setMonth(self,month):
        if 1 <= month <= 12: # 유효성 체크
            self.__inner_month = month
        print("setMonth() call")
    
    month = property(getMonth,setMonth)

# help(MyDate)
today = MyDate(10)
# today.month = 15 # setMonth() call 호출
today.__inner_month = 15 # private 이 되서 세팅 안된것
print(today.month)
getMonth() call
10

 

property를 이용한 setter,getter

필드에 접근할 때 getter/setter를 이용하지 않고 직접 필드를 호출하여 사용 가능.
하지만 내부적으로는 getter/setter 메서드를 통해 값을 읽고 쓰게 된다.

getter 메서드 앞: @property
setter 메서드 앞: @<필드명>.setter

 

@property 데코레이터를 이용한 sette/getter 방법

class MyDate:
    def __init__(self,month):
        # 가급적 멤버변수의 이름을 어렵게 설정
        self.__inner_month = month

    @property # getter 읽
    def month(self):
        print("getMonth()call")
        return self.__inner_month

    @month.setter #setter
    def month(self,month):
        if 1 <= month <= 12: # 유효성 체크
            self.__inner_month = month
        print("setMonth() call")


today = MyDate(10)
# print(today.month)
today.month = 12
print(today.month)
setMonth() call
getMonth()call
12

 

사용자 정의 예외 클래스

특정 상황에 맞는 예외 클래스를 프로그래머가 직접 만들어 사용 하는 것

Exception  클래스를 상속받아서 만든다.(? 모든 예외 클래스의 super = Exception 이기 때문)
    - 생성자에서 부모클래스의 생성자를 호출해서 예외메세지 전달
    - __str__ 메서드를 오버라이딩 하여 예외 메세지를 설정

class MyException(Exception):
    def __init__(self,msg):
        super().__init__(msg)

    def __str__(self):
        return 'My Exception'    # 에러메세지에서 확인 가능
num = int(input("양의 정수 입력"))
if num <= 0:
    raise MyException('양의 정수만 입력하세요') 
else:
    print(num)
양의 정수 입력 -3

 

---------------------------------------------------------------------------
MyException                               Traceback (most recent call last)
Cell In[16], line 3
      1 num = int(input("양의 정수 입력"))
      2 if num <= 0:
----> 3     raise MyException('양의 정수만 입력하세요')
      4 else:
      5     print(num)

MyException: My Exception

설정한 오류 발생

 

class 메서드

특정 객체에 대한 작업을 처리하는 것이 아니라 클래스 전체가 공유 (클래스 1: 객체 n)

class Car:
    serial = 0 
    # Car 클래스 소속 변수. 특정 객체에 소속되지 않으며 이 클래스로 부터 생성되는 모든 객체가 공유한다.

    def __init__(self,name):
        self.name = name
        Car.serial += 1 # Car 클래스에서 객체가 생성될때 마다 1씩 더해진다.
        self.serialNO = Car.serial
        # 객체 생성하며 값을 받아오는게 아니기 때문에 매개변수로 포함하지 않는다.

    @classmethod
    def lastSerialNo(cls):
        print(cls.serial)

sonata = Car("쏘나타")
grandure = Car("그랜져")
#  객체 2 개 생성

print(f"{sonata.name} 시리얼번호 {sonata.serialNO}")
print(f"{grandure.name} 시리얼번호 {grandure.serialNO}")
Car.lastSerialNo()
# 이전 생성된 객체에서 유지하며 다음 객체 생성에서 누적함    
# 클래스 변수는 모든 객체에서 공유 된다는 것을 알 수 있음
쏘나타 시리얼번호 1
그랜져 시리얼번호 2
2

 

 

연산자 메서드

class Date:
    def __init__(self,year,month,day):
        self.year =year
        self.month = month
        self.day = day
        
    # 메서드의 이름 .... 리턴값까지 같아야함
    def __eq__(self, other): #  other는 비교 대상으로 사용될 다른 객체
        return self.year == other.year and self.month == other.month and self.day == other.day

    def __gt__(self,other):
        if self.year>other.year: 
            return True
        elif self.year == other.year and self.month > other.month:
            return True
        elif self.year == other.year and self.month == other.month and self.day > other.day:
            return True
        else: return False
            
d1 = Date(2023,10,26)
d2 = Date(2023,10,25)

# print(d1==d2) # 참조값이 다르기 때문에 False ::  __eq__ (object)
print(d1==d2) #  __eq__ (object) 를 재정의 해줌으로써 True
# d1: self , d2: other

# print(d1+d2) # err __add__ (int) object에 없음 
print(d1>d2)
False
True

 

'국비 교육 > 파이썬' 카테고리의 다른 글

[파이썬] 예외(Exception)  (0) 2023.12.28
[파이썬] File I/O , File 과 Directory  (0) 2023.11.05
[파이썬] 함수 - 2  (0) 2023.11.05
[파이썬] 함수 -1  (0) 2023.11.05