iter 메소드가 있다는 것은 for를 사용해 순회하며 next() 를 이용 한다는 것!
__x
등 과 같이 더블 언더스코어 변수는 private
하다. 파이썬 코드 컴벤션
# 프로퍼티 메타 디스크립션. 데코레이터를 활용한 디스크립션이 걸리는것.
# class 선언
class VectorP(object):
# private 선언
def __init__(self, x, y):
self.__x = float(x)
self.__y = float(y)
def __iter__(self):
return (i for i in (self.__x, self.__y)) # Generator
# @property 마치 getter
@property
def x(self):
return self.__x
# @x.setter 는 getter에 따라온다 무조건 뒤에 위치할 수 밖에없다.
# 앞에 안됨 반드시 뒤에 있거나 없거나
@x.setter
def x(self, v):
self.__x = v
@property
def y(self):
return self.__y
@y.setter
def y(self, v):
if v < -273:
raise ValueError("Temperature below -273 is not possible")
self.__y = v
# 객체 선언
v5 = VectorP(20, 40)
slot
파이썬 인터프리터에 통보하는 기능을 한다. 해당 클래스가 가지는 속성을 제한함.
dict 속성 최적화로 다수 객체 생성시 메모리 공간 효율 좋다! 약 20% 절약
해당 클래스에 만들어진 인스턴스 속성 관리에 딕셔너리 대신 set 형태 사용
class TestA(object):
__slots__ = ('a',)
class TestB(object):
pass
use_slot = TestA()
no_slot = TestB()
print('EX2-1 -', use_slot)
# print('EX2-2 -', use_slot.__dict__)
print('EX2-3 -', no_slot)
print('EX2-4 -', no_slot.__dict__)
use_slot.a = 10
# use_slot.b = 10
# 메모리 사용량 비교
import timeit
# 측정을 위한 함수 선언
def repeat_outer(obj):
def repeat_inner():
obj.a = 'test'
del obj.a
return repeat_inner
print('EX3-1 -', min(timeit.repeat(repeat_outer(use_slot), number=1000)))
print('EX3-2 -', min(timeit.repeat(repeat_outer(no_slot), number=1000)))
print()
print()
# 객체 슬라이싱
class ObjectS:
def __init__(self):
self._numbers = [n for n in range(1, 10000, 3)]
def __len__(self):
return len(self._numbers)
def __getitem__(self, idx):
return self._numbers[idx]
s = ObjectS()
print('EX3-1 -', s.__dict__)
print('EX3-2 -', len(s._numbers))
print('EX3-3 -', len(s))
print('EX3-4 -', s[1:10])
print('EX3-5 -', s[-1])
print('EX3-6 -', s[::10])
파이썬 추상 클래스
참고 : https://docs.python.org/3/library/collections.abc.html
# Sequence 상속 받지 않았지만, 자동으로 __iter__, __contains__ 기능 작동
# 객체 전체를 자동으로 조사 -> 시퀀스 프로토콜
from collections.abc import Sequence
# Sequence 상속
# 요구사항인 추상메소드 모두 구현해야 동작
# 슬라이싱 가능한 객체 구현
class IterTestB(Sequence):
def __getitem__(self, idx):
return range(1, 50, 2)[idx] # range(1, 50, 2)
def __len__(self, idx):
return len(range(1, 50, 2)[idx])
i2 = IterTestB()
print(i2[4])
추상 클래스 만들기 활용
import abc
class RandomMachine(abc.ABC): # metaclass=abc.ABCMeta (3.4 이하 버전)
# __metaclass__ = abc.ABCMeta
# 추상 메소드
@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()
구현
# 서브 클래스 확인
# issubclass(obj_x, obj_y) obj_x 가 obj_y 자식 클래스일때 True
print(issubclass(RandomMachine, CraneMachine))
# False
print(issubclass(CraneMachine, RandomMachine))
# True
# 상속 구조 확인
print(CraneMachine.__mro__)
# (<class '__main__.CraneMachine'>, <class '__main__.RandomMachine'>, <class 'abc.ABC'>, <class 'object'>)
cm = CraneMachine(range(1,100)) # 추상메소드 구현 안하면 에러
print(cm._items)
print(cm.pick())
print(cm())
print(cm.inspect())