Class Structure #3 파이썬 추상클래스(abc)

정은경·2020년 5월 5일

1. 학습목표

  • 객체 슬라이싱
  • 추상 클래스

2. 학습내용

# 객체 슬라이싱c
class ObjectS():
    def __init__(self):
        self._numbers = [n for n in range(1, 10, 3)]

    def __len__(self):
        return len(self._numbers)

    def __getitem__(self, idx):
        return self._numbers[idx]


s = ObjectS()
# print('EX3-1 -', s.__dict__)
# EX3-1 - {'_numbers': [1, 4, 7]}
# print('EX3-2 -', len(s))
# EX3-2 - 3
# print('EX3-4 -', s[1:2])
# EX3-4 - [4]


# 파이선 추상클래스
# 참고 : https://docs.python.org/3/library/collections.abc.html

# 추상클래스는 자체적으로 객체 생성 불가!
# 추상클래스는 상속을 통해서 자식 클래스에서 인스턴스를 생성해야 함
# 추상클래스를 사용하는 이유:
# 개발과 관련된 공통된 내용(필드, 메소드) 추출 및 통합해서 공통된 내용으로 작성하게 하는 것
# 반드시 상속받아야하는 속성을 강제한는 것?!


# sequence 삭송 받지 않았지만, 자동으로 __iter__, __contain__ 기능 작동하도록 함!
# 객체 전체를 자동으로 조사 -> 시퀀스 프로토콜

class IterTestA():
    def __getitem__(self, idx):
        return range(1, 50, 2)[idx]

i1 = IterTestA()
# print('EX4-1 -', i1[4])
# EX4-1 - 9
# print('EX4-2 -',i1[4:10])
# EX4-2 - range(9, 21, 2)
# print('EX4-2 -',3 in i1[1:10])
# EX4-2 - True

## iterator를 구현하지 않았지만 파이썬이 똑똑하게 작동하도록 함
# print('EX4-3 -', [i for i in i1])
# EX4-3 - [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49]



# Sequence 상속
# 요구사항인 추상메소드를 모두 구현해야 동작
# FM으로 구현했을 때는, 반드시 추상메소드를 모두 구현해야 동작하는 지 테스트!!
# 결론은 "추상"메소드를 상속받으면! 반드시 오버랑이딩 해줘야함!
from collections.abc import Sequence

class IterTestB(Sequence):
    def __getitem__(self, idx):
        return range(1, 50, 2)[idx]

# i2 = IterTestB()
"""
Traceback (most recent call last):
  File "/Users/marie/PycharmProjects/untitled1/fc_lecture.py", line 63, in <module>
    i2 = IterTestB()
TypeError: Can't instantiate abstract class IterTestB with abstract methods __len__
"""


class IterTestC(Sequence):
    def __getitem__(self, idx):
        print('__getitem__,', idx)
        return range(1, 50, 2)[idx]

    def __len__(self, idx):
        print('__len__', idx)
        return len(range(1, 50, 2)[idx])

i3 = IterTestC()
# print('EX5-1 -', i3[4])
"""
__getitem__, 4
EX5-1 - 9
"""
# print('EX5-1 -', i3[4:10])
"""
__getitem__, slice(4, 10, None)
EX5-1 - range(9, 21, 2)
"""
# print('EX5-1 -', 3 in i3[1:10])
"""
__getitem__, slice(1, 10, None)
EX5-1 - True
"""



## abc 활용 예제
import abc

class RandomMachine(abc.ABC): # metaClass = abc.ABCMeta (3.4 이하)
    # __metaclass__ = abc.ABCMEta

    # 추상 메소드
    # 추상메소드는 메소드 위에 데코레이터료 표시함!
    # 추상 메소드는 자식에서 반드시 구현되어야 함(강제성!)
    # 추상 메소드가 아닌 것은 자식에서 반드시 구현되지 않아도 됨!
    ## 추상클래스에서 이렇게 데코레이터로 annotation된 메소드는 상속받은 자식에서 반드시 구현되어야함!!(강제!)
    @abc.abstractmethod
    def load(self, iterobj):
        '''Iterable 항목 추가'''

    # 추상 메소드
    @abc.abstractmethod
    def pick(self, iterobj):
        '''무작위 항목 뽑기'''

    def inspect(self):
        items = []
        while True:
            try:
                items.append(self.pick())
            except LookupError:
                break
            return tuple(sorted(items))


import random

class CraneMachine(RandomMachine):
    def __init__(self, items):
        self._randomizer = random.SystemRandom()
        self._items = []
        self.load(items)

    def load(self, items):
        self._items.extend(items)
        self._randomizer.shuffle(self._items)

    def pick(self):
        try:
            return self._items.pop()
        except IndexError:
            raise LookupError('Empty Crane Box')

    def __call__(self):
        return self.pick()


# 서브 클래스 확인
# print('EX5-1 -', issubclass(RandomMachine, CraneMachine))
# EX5-1 - False
# print('EX5-2 -', issubclass(CraneMachine, RandomMachine))
# EX5-2 - True


# 상속 구조 확인
# print('EX5-3 -', CraneMachine.__mro__)
"""
EX5-3 - 
(<class '__main__.CraneMachine'>, 
<class '__main__.RandomMachine'>, 
<class 'abc.ABC'>, 
<class 'object'>)
"""


cm = CraneMachine(range(1, 100))

# print('EX5-4 -', cm._items)
# EX5-4 - [3, 73, 74, 99, 1, 71, 46, 24, 13, 80, 54, 62, 47, 10, 64, 31, 69, 81, 51, 70, 9, 72, 45, 4, 16, 30, 33, 17, 28, 79, 7, 55, 89, 84, 27, 22, 19, 66, 23, 41, 39, 90, 14, 11, 68, 85, 8, 37, 2, 32, 98, 43, 76, 92, 95, 59, 5, 48, 65, 67, 82, 91, 77, 97, 15, 83, 18, 58, 87, 78, 93, 57, 34, 29, 52, 40, 12, 36, 25, 56, 61, 26, 88, 75, 60, 6, 63, 94, 49, 21, 38, 96, 86, 50, 44, 42, 35, 53, 20]
# print('EX5-5 -', cm.pick())
# EX5-5 - 10

# callable 메소드 확인
# print('EX5-6 -', cm)
# EX5-6 - <__main__.CraneMachine object at 0x102e4eb00>

# inspect 메소드는 부모 클래서에서 일반메소드임 (추상메소드 아님)
# print('EX5-7 -', cm.inspect())
# EX5-7 - (28,)

3. 느낀 점

profile
#의식의흐름 #순간순간 #생각의스냅샷

0개의 댓글