Composite pattern의 활용
composite pattern 중 하나의 속성은 inheritance를 대신 할 수 있음
class A:
class C:
class B:
def __init__(self):
self.a = A()
self.c = B()
def multi(self):
return self.a * self.b
class AA:
a = 1
def aaaa(slef, x):
self.b = x
def aaa(self):
return self.b
class BB(AA):
pass
상속의 문제점 : AA와 coupling. 밀접하게 연결이 되어 있어서, class AA가 바뀌면 class BB의 기능도 바뀌어짐.
class CC: ## AA가 변할 때 같이 안 변함
a = 1 # overiding처럼 작동함
def __init__(self):
self.y = AA()
def aa(self, x):
self.y.b = x
def aaa(self):
return self.y.b
class DD: ## AA가 변할 때 같이 안 변함
a = 1 # overiding처럼 작동함
def __init__(self):
self.y = AA()
def aa(self, x):
self.y.aa(x)
def aaa(self):
return self.y.aaa()
파이썬의 inheritance는 delegate
BB.a가 없으면 AA것을 찾음(delegate) -> BB를 overiding 하지 않은 상태에서 AA가 값이 바뀌어버리면 값이 그대로 들고 옴. self.y.b는 인스턴스이기 때문에 변하지 않음
인스턴스가 수십개 있을 경우, 수정해야 하는 것들이 넘쳐나기 때문에 composition 방식을 사용
class EE:
a = 1
def __init__(self):
self.y = Aa()
def aa(self): # overriding 처럼 사용 가능
print('aa')
def __getattr__(self, x): # try: attribute arror, attribute를 이름으로 반환함
return getattr(self.y, x)
참조가 안 될 때 attribute 에러가 발생함. 그런데 getattr가 정의되어 있고, 인스턴스에 attribute error가 발생하면 getattr가 실행 됨.
a = [1, 2, 3]
getattr(a, 'pop')() #attribute는 이름으로 반환
>> 3
class EE:
a = 1
def __init__(self):
self.y = Aa()
def aa(self): # overriding 처럼 사용 가능
print('aa')
def __getattribute__(self, x): # .에 대해 어떻게 처리 해야 할지 알려주는 것
return getattr(self.y, x)
_ (underbar)의 의미
- _name 의미 : 내부적으로만 사용
- from om X import *할 때 딸려오지 않는다.
- 자동완성이 안 됨
=> 내부적으로만 사용하겠다고 암시
- _name : i18n (internationalization)
- name_ : python에 있는 것과 충돌 방지용 (관례)
np.int_ : numpy에서 재정의한 int - _ : 사용하지 않을 변수 (관례)
- __name : mangling(private 비슷하게 사용), 이름이 변함
class X: __a = 1 print(X._x__a) >> 1
- _ : interactive last result, _ 변수 이전 마지막 result를 가지고 옴
- x : double underbar (dundu / magic(special) method)
cf. sklearn에서는 dir(iris) 결과에 _가 없는 이유
__all__ = [a, _a] # * 로 import 할 때 지정할 수 있음
__slot__ # 접근하지 못하게 할 수 있음
Descriptor
g.a = 1 # setter in oop
g.a # getter
del g.a # deleter
setter, getter, deleter할 때 조작을 할 수 있는 것 -> descriptor
descriptor를 통해 사용자들이 값을 사용 못하게 하거나, 값을 숨길 수 있음
Descriptor를 만드는 방법
# 1
class Name:
def __init__(self):
self._name = ''
def __get__(self, instance, owner):
return self.name
def __set__(self, instance, name):
self.name = name
def __delete__(self, instance):
del self._name
class Person:
name = Name()
p = Person()
# 2
class Person2:
def __init__(self):
self._name = ''
def fget(self):
return self.name
def fset(self, name):
self.name = name
def fdelete(self):
del self._name
name = property(fget, fset, fdel)
p2 = Person2()
#3
class Person3:
def __init__(self):
self._name = ''
@property
def name(self):
return self.name
@property.setter
def name(self, name):
self._name = name
@property.deleter
def name(self):
del self.name
p3 = Person3()
- else : if else, for/while else, try else
- from : from import, raise from, yield from
- as : import as, except as, with as
Metaclass
원래 instance를 무제한으로 쓸 수 있으나 1개의 instance만 만들 수 있게 class의 기능을 변경
meta class : class의 class. class의 기능을 바꿀 수 있음
a = 0
type(a)
>> int
type(int)
>> type
type 자체가 class의 class, 즉 meta class임
class Singleton(type): # metaclass를 상속해서 metaclass를 만듦
_instance = None
def __call__(cls):
if cls ._instance is None:
cls._instance = super().__call__()
return cls._instance
class Myclass(metaclass=Singleton):
pass
m = Myclass()
s = Myclass()
m.a = 1
s.a
>> 1
s.bb = 3
m.bb
>> 3
k = Myclass()
k.bb
>> 3
s is k
>> True
class의 instance가 None이면, 새로 만들고 None이 아니면 기존의 클래스를 불러와라 -> instance를 1개만 만들도록 class의 기능을 변경함
meta class : class의 기능을 변경하는 것
composition 방식 다른 class의 instance를 안에 집어넣어서 행동하게 하는 것 composition 방식을 활용하여 상속을 대신하는 기법도 있고, descriptor를 만들 수도 있음
composition 방식에 다양한 활용이 있는 것 처럼, meta class의 활용도 다양함
머신러닝에서는 abstract base class를 주로 사용함.
abstract란 규칙을 따른 다는 것. 공통되는 규칙을 따라서, 차이점만 새로 구현하도록 하는 방식.
예로, sklearn 패키지의 Navie_bayes에 변형들이 많음. 공통적인 부분만 뽑아놓고, 차별적인 것만 구현하도록 하면 사용자들은 규칙만 따른다면, 각각의 Navie_bayes 알고리즘을 만들 수 있음
from skleran.navie_bayes import BernoulliNB, CategoricalNB, MultinomialNB
python에서 제공하는 class의 기능을 모두 바꿀 수 있음 -> 확장성
meta class 기능 중 abstract base class는 공통 기능을 뽑아놓고, 기능을 강제 시킴
#ABCMeta는 abstract base class 형태로 기능을 바꿈(meta clasS), abstractmethod는 기능을 강제적으로 구현하게 하는 method
from abc import ABCMeta, abstractmethod
class A(metaclass=ABCMeta):
@abstractmethod
def a(self):
pass
class B(A):
def a(self):
print('a')
b = B()
B에서 abstractmethod를 구현하지 않으면 ImplementedError 발생함
class S(tf.keras.utils.Sequence): # duck-typing 방식으로 meta class를 받음
pass
'공부하는삶 > Python' 카테고리의 다른 글
[TIL] FastAPI 응답과 오류 처리 HTTPException (0) | 2023.09.25 |
---|---|
Python numpy, tensorflow, pytorch array (0) | 2023.08.29 |
Python (Avoiding) Flow Control (0) | 2023.08.29 |
Sequence (0) | 2020.05.09 |
Magic Method (0) | 2020.05.09 |
Gaussian Filter vs Bilateral Filter (0) | 2020.04.02 |