상세 컨텐츠

본문 제목

7-2. 클래스

Python

by evaseo 2021. 4. 25. 18:31

본문

 

1.    상속

(1)     형식
class
클래스1 이름(상속할 클래스2 이름):

(2)     특징

1)       클래스1은 클래스2의 모든 멤버를 상속받으므로 클래스2의 모든 기능을 사용가능

2)       추가로 자기자신의 기능(고유 변수, 메소드 추가)도 사용 가능 - 클래스의 기능 확장

3)       기존 클래스가 라이브러리 형태로 제공되거나 수정이 허용되지 않는 상황에서 클래스를 변경하지 않고 기능을 추가하거나 기존 기능을 변경하려고 할 때 사용

(3)     메소드 오버라이딩(overriding 덮어쓰기): 부모 클래스에 있는 메서드를 동일한 이름으로 다시 만드는 것

1)       오버라이딩할 때는 꼭 부모의 변수를 사용할 필요는 없다. 처음에 데이터형을 정의하지 않기 때문에

# 클래스 상속연습
class Person:
    say = '난 사람이야' #public
    nai = 20
    __kbs = '공용방송' # __변수명: private 현재 클래스에서만 참조 가능
    
    def __init__(self, nai):
        print('person생성자')
        self.nai = nai #각각의 instance에서 달라질 수 있다고 뜻
        
    def printInfo(self):
        print('나이:{}, 이야기:{}'.format(self.nai, self.say))
        
    def hello(self):
        print('헬로우')
        print('hello: ', self.say, self.__kbs)
pe = Person(22)
pe.printInfo()
pe.hello()        
#자식클래스가 공통적으로 가질 멤버를 구성해 놓음
print()
#------------------------------------------------------------------------------------------------
print('Employee-------------------------------------------------------------')
print()

class Employee(Person):
    say = '일하는 동물' # 자식과 동일한 멤버변수에 의해 부모의 say가 숨겨짐(은닉화)
    subject = '근로자' #Employee 고유멤버
    
    def __init__(self):
        print('Employee생성자')
    
    def printInfo(self): # 자식과 동일한 멤버메소드에 의해 부모의 메소드가 숨겨짐(은닉화)
        print('Employee의 printInfo 메소드')
        
    def empShow(self):
        say = '수다떨기'
        print(say) # '수달떨기' -> 없다면 모든 클래스 밖의 모듈의 say찾기. 그래도 없으면 error
        print(self.say) # 현재 class의 say, 없으면 부모class의 say 
        print(super().say) # 무조건 부모 class의 say
        self.printInfo() # 현재 class의 printInfo, 없으면 부모class의 printInfo
        super().printInfo() # 무조건 부모 class의 printInfo

       
emp = Employee()
print(emp.say, emp.nai)
print(emp.subject)
emp.printInfo()
print()
emp.empShow()
print()
print('Worker-------------------------------------------------------------')
'''
class Worker(Person):
    pass

wo = Worker(33)
print(wo.say, wo.nai)
wo.printInfo()
'''
class Worker(Person):
    hobby = '코딩'
    
    def __init__(self, nai):
        print('Worker 생성자')
        #나이를 받아서 부모에게 주고 싶다면
        #자바는 자식의 생성자를 부르면 부모도 호출되는데 파이썬은 명시적으로 불러줘야 부모에게 할 수 있다.
        super().__init__(nai) #bound method call
        #== Person.__init__(self, nai) #unbound call 원형클래스의 이름으로 부른 것

    def woShow(self):
        self.printInfo()
        super().printInfo()

wo = Worker(33)
wo.woShow()

print()
print('Programmer-------------------------------------------------------------')
class Programmer(Worker):
    def __init__(self, nai):
        print('Programmer 생성자')
        Worker.__init__(self, nai)
    
    def prShow(self):
        self.printInfo()
        super().printInfo()
        #super().super()는 없음
    
    def kbsShow(self):
        print(self.__kbs)
    
    
pr = Programmer(35)
print(pr.say, pr.nai)
pr.hello()
pr.prShow()
# pr.kbsShow() error ∵ __kbs는 private라서
print('\n클래스 타입 확인-------------------')
a=3
print(type(a))
print(type(pr))
print()

#부모클래스 확인하기
print('부모클래스 확인하기---------------------')

print(Programmer.__bases__)
print(Worker.__bases__)
print(Person.__bases__)​
실행결과

 

2.    다중상속

예제1)

# 다중상속 - 순서가 중요(자바에서는 지원하지 않음)
print('어쩌구 저쩌구 하다가... 다중상속 필요')

class Tiger: # 최상위 클래스 Object를 상속받고 있는 거임
    data = '호랑이 세상'
    
    def cry(self):
        print('호랑이 울부짖음')
        
    def eat(self):
        print('맹수는 고기를 먹음')
        
class Lion:
    data = '사자세상'
    
    def cry(self):
        print('백수의 왕 으르렁')    
        
    def hobby(self):
        print('사자의 취미는 낮잠')

class Liger(Tiger, Lion):
    pass

aa = Liger()
aa.cry() # 먼저 적은 cry()가 출력됨. Tiger를 Lion보다 먼저 상속받는 괄호안에 적었으니 '호랑이 울부짖음'만 나옴
aa.eat()
print(aa.data)
aa.hobby()
print()

class Liger2(Lion, Tiger):
    data = '라이거 멤버변수'
    
    def play(self):
        print('라이거2 고유메소드')
        self.hobby()
        super().hobby()
        print(self.data)
        print(super().data)

bb = Liger2()
bb.cry()
bb.eat()
bb.hobby()
print(bb.data)
print()
bb.play()​
실행결과

 

예제2)

class Animal:
    def move(self):
        pass #오버라이딩 해주길 기대, 강요는 아님. 자식클래스에서 오버라이딩을 강요하고 싶으면 추상메소드를 이용. 다형성 구사를 위해 오버라이딩 강요
    
class Dog(Animal):
    name = '개'
    
    def move(self):
        print('개는 낮에 돌아다님')

class Cat(Animal):
    name = '고양이'
    
    def move(self):
        print('고양이는 밤에 움직임')
        print('눈빛이 빛남')

class Wolf(Dog, Cat):
    pass

class Fox(Cat, Dog):
    def move(self):
        print('오버라이딩: 나는 여우라고 해')

    def foxMethod(self):
        print('여우 고유 메소드')

dog = Dog()
cat = Cat()
wolf = Wolf()
fox = Fox()

anis = [dog, cat, wolf, fox]
for a in anis:
    a.move()​

 

실행결과

 

3.    추상클래스

(1)     추상 메소드를 가진 클래스

(2)     자식클래스에서 부모의 추상 메소드를 일반 메소드로 반드시 오버라이딩하게 하는 목적으로 사용

 

예제1)


 

예제2)

from abc import *

class Employee(metaclass = ABCMeta):
    def __init__(self, irum, nai):
        self.irum = irum
        self.nai = nai
        
    @abstractmethod
    def pay(self):
        pass

    @abstractmethod
    def data_print(self):
        pass
    
    def irumnai_print(self):
        print('이름: '+ self.irum + ', 나이: '+ str(self.nai), end = ' ')

class Temporary(Employee):
    def __init__(self, irum, nai, ilsu, ildang):
        Employee.__init__(self, irum, nai) #irum과 nai를 가지고 부모에게 전달
        self.ilsu = ilsu
        self.ildang = ildang
    
    def pay(self): #강요된 오버라이딩
        return self.ilsu * self.ildang
    
    def data_print(self): #강요된 오버라이딩
        self.irumnai_print()
        print(', 월급: '+ str(self.pay()))
        
# 클래스를 처음에는 pass로 해놓고 호출하는 방식을 먼저 보고 다음에 pass를 지우고 호출방식에 맞게 수행할 문장 작성
t = Temporary('홍길동',24,20,15000) #생성자를 부르면서 irum, nai, ilsu, ildang를 입력하니깐 Temporary클래스에도 이런 것을 다 받을 수 있는 생성자를 선언해야함
t.data_print()
#자식Temporary에게 저장된 '홍길동',24을 가져다가 부모클래스Employee의 irumnai_print가 가져다 씀

class Regular(Employee):
    def __init__(self,irum, nai,salary):
        super().__init__(irum, nai) # Regular의 super()는 Employee, super()를 쓸 때는 self를 매개변수로 가지면 안됨
        self.salary = salary
        
    def pay(self): #강요된 오버라이딩
        return self.salary
    
    def data_print(self): #강요된 오버라이딩
        self.irumnai_print()
        print(', 급여: ' + str(self.pay()))
        
r = Regular('한국인',27,3500000)
r.data_print()


class SalaryMan(Regular):
    def __init__(self, irum, nai, salary, sales, commission):
        super().__init__(irum, nai,salary)
        self.sales = sales
        self.commission = commission
    
    def pay(self): # 일반메소드를 오버라이딩
        return super().pay() + int(self.sales * self.commission)
    
    def data_print(self): # 일반메소드를 오버라이딩
        self.irumnai_print()
        print(', 수령액: ' + str(self.pay()))
    
    """def data_print(self):
        self.irumnai_print()
        print(', 수령액: ' + str(super().pay() + int(self.sales * self.commission)))"""
    
s = SalaryMan('손오공', 29, 1200000, 5000000, 0.25)
s.data_print()​
실행결과

 

예제2의 관계)


 

4.    클래스변수

(1)     클래스 내에서 선언된 변수

(2)     객체변수와 다르게 클래스로 만든 모든 객체에 공유된다.

(3)     Z클래스의 객체가 a, b일 때 Z클래스의 클래스변수가 변경되면 a.클래스변수와 b.클래스변수가 모두 변경된다.

      => 모두 같은 메모리 주소를 공유하기 때문

'Python' 카테고리의 다른 글

8. 사용자 입력과 출력  (0) 2021.04.29
9. 파일 읽고 쓰기 File I/O  (0) 2021.04.25
7-1. 클래스  (0) 2021.04.25
6. 모듈(module)  (0) 2021.04.25
5. 함수  (0) 2021.04.25

관련글 더보기