diff --git a/_posts/2023-01-06-deep-dive-super.markdown b/_posts/2023-01-06-deep-dive-super.markdown new file mode 100644 index 0000000..cc3a0f0 --- /dev/null +++ b/_posts/2023-01-06-deep-dive-super.markdown @@ -0,0 +1,107 @@ +--- +layout: single +title: "Deep Dive super() in python" +date: 2023-01-06 11:56:13 +0900 +categories: python language +toc: true +toc_sticky: true +tags: python +comments: true +enable_copy_code_button: true +--- + + +어느 언어에서든 super 는 상속하는 parent class 를 가져오는 keyword 다. single inheritance 인 경우밖에 없다면 이 문서를 작성할 필요도 없었을텐데, 복잡한 인자를 사용한 경우를 만났는지 링크를 남겨두었고, 미래의 내가 문서를 작성하고 있다. + +## bound/unbound method + +- bound method + - 어떤 클래스에 속해있는 메소드 +- unbound method + - class instance 를 인자로 받지 않는 메소드 + - 파이선 3으로 올라오면서 사라진 개념임 + - instance 를 받지 않는 것은 static_method 로서 만들수는 있음. + +```python +# adding a method to existing object +>>> def bar(self): +... print ("bar") +... +>>> +>>> +>>> bar + +>>> class A: +... pass +... +>>> +>>> A.bar=bar +>>> A.bar + +>>> A.bar= bar.__get__(A) +>>> +>>> A.x +> + +``` + +## Descriptor + +https://docs.python.org/3.7/howto/descriptor.html + +## Multiple Inheritance + +`Cube` → `Square` → `Rectangle` 의 상속 관계에서 Cube 에서 Rectangle 의 area 가 아닌 Square 의 area method 를 사용하고 싶은 경우 아래와 같이 사용할 수 있다. + +```python +class Cube(Square): + def surface_area(self): + face_area = super(Square, self).area() + return face_area * 6 +``` + +보통 multiple inheritance 라고 하면 이런 형태의 연쇄 상속이 아니고 아래와 같은 형태일 것이다. + +``` +superclass1 superclass2 + \ / + subclass +``` + +모든 superclass 가 .area 메소드를 정의하고 있다면 python 은 super().area() 를 호출했을 때 어떤 것을 가져올까? + +`method resolution order` 가 결정해줄 것이다. + +## Method Resolution Order + +모든 클래스는 `.__mro__` attribute 을 지니고 있다. 이는 super() 를 했을 때 어떤 class 를 우선적으로 탐색해서 가져올지 알려준다. + +```python +class RightPyramid(Triangle, Square): + def __init__(self, base, slant_height): + self.base = base + self.slant_height = slant_height + + def area(self): + base_area = super().area() + perimeter = super().perimeter() + return 0.5 * perimeter * self.slant_height + base_area +``` + +위의 코드에서 RightPyramid 의 상속 구문에서 Triangle 이 더 앞에 있기 때문에 mro 는 우선적으로 Triangle 을 찾게 될 것이다. +또, Square 가 Rectangle 을 상속했기 때문에 Square 를 우선적으로 볼 것이다. + +```python +>>> RightPyramid.__mro__ +(, , + , , + ) + +``` + +그러니... mro 에 의존할 것이 아니고 super 를 사용할 때 사용할 class 를 명시하는 게 권장될 것 같다. + +## 참고 + +- [bound/unbound method](https://www.geeksforgeeks.org/bound-unbound-and-static-methods-in-python/) +- [deep dive super](https://realpython.com/python-super/) diff --git a/_posts/2023-01-06-signleton-python.markdown b/_posts/2023-01-06-signleton-python.markdown index cd11633..edb4055 100644 --- a/_posts/2023-01-06-signleton-python.markdown +++ b/_posts/2023-01-06-signleton-python.markdown @@ -1,2 +1,118 @@ +--- +layout: single +title: "Singleton approach in python" +date: 2023-01-06 11:56:13 +0900 +categories: python language +toc: true +toc_sticky: true +tags: python +comments: true +enable_copy_code_button: true + +--- + + +c++ 의 경우에 보통 static variable 을 이용해서 구현하는 것이 일반적인데 반해 python 에서 singleton 을 구현하는 방법은 딱히 idiomatic 하게 정해져있지 않다. +static 변수나 전역 변수를 만드는 것은 그렇게 유쾌한 경험을 제공해주지 않는다. +결론부터 말하자면 참고하는 문서에서는 Metaclass 방식을 가장 선호하는 방법으로 추천한다. 테스트하기에 좋기 때문. + +## 구현 후보 + +### Metaclass + +생성시에 class 를 변경할 수 있는 특별한 방법을 제공. 어떤 class 로 instance 를 생성한 것이 있다면 instance 를 또 생성하지 않게 하는 metaclass 를 만들 수 있음 . + +```python +class Singleton(type): + _instances = {} + + def __call__(cls, *args, **kwargs): + if cls not in cls._instances: + cls._instances[cls] = super(type(cls), cls).__call__(*args, **kwargs) + return cls._instances[cls] + +class _A(): + def __init__(self, name): + self.name = name + + +class A(_A, metaclass=Singleton): + pass +``` + +### Decorator + +decorator 를 이용해서도 구현할 수 있음. +```python + +def singleton(class_): + instances = {} + + def get_instance(*args, **kwargs): + if class_ not in instances: + instances[class_] = class_(*args, **kwargs) + return instances[class_] + + return get_instance + + +@singleton +class A: + def __init__(self, name): + self.name = name + + + +``` + +### Classic singleton ( allocation) + +원래 클래스가 제공하는 기능인 `__new__` 메소드를 이용. + +```python + + +class A: + initialized = False + name = None + + def __init__(self, name): + if not self.initialized: + self.name = name + self.initialized = True + + def __new__(cls, url, *args, **kwargs): + if not cls._instance: + cls._instance = super(Database, cls).__new__(cls, *args, **kwargs) + return cls._instance + + + + +``` + +## 장단점 비교 + +* Metaclass + * 장점 + * test 를 할 때 singleton 기능없이 순순하게 해당 class 가 잘 동작하는지 구분해서 확인해볼 수 있음. + * 예를 들면 _A 에 대한 객체를 하나 생성해서 기능 테스트 가능 + * 단점 + * decorator 에 비해 `metaclass=` 의 인자를 넣어줘야한다는 것이 귀찮음 +* Decorator + * 장점 + * 여러 클래스에 쉽게 적용하기 좋음 + * 코드 양이 가장 적음 + * 단점 + * test 시에 singleton 특성을 분리하기 어려움. +* Classic + * 장점 + * 초창기 python 의 문법만 알고있어도 구현을 이해하는데 문제 없음 + * 단점 + * 코드가 지저분함 + * 여러 클래스에 적용하기 어려움 + +## 참고 + https://itnext.io/deciding-the-best-singleton-approach-in-python-65c61e90cdc4 -https://realpython.com/python-super/ +