Skip to content

Commit

Permalink
python update
Browse files Browse the repository at this point in the history
  • Loading branch information
m1ser4ble committed Nov 2, 2024
1 parent 328f0db commit 28a41d7
Show file tree
Hide file tree
Showing 2 changed files with 224 additions and 1 deletion.
107 changes: 107 additions & 0 deletions _posts/2023-01-06-deep-dive-super.markdown
Original file line number Diff line number Diff line change
@@ -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
<function bar at 0x1033828e0>
>>> class A:
... pass
...
>>>
>>> A.bar=bar
>>> A.bar
<function bar at 0x1033828e0>
>>> A.bar= bar.__get__(A)
>>>
>>> A.x
<bound method bar of <class '__main__.A'>>

```

## 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__
(<class '__main__.RightPyramid'>, <class '__main__.Triangle'>,
<class '__main__.Square'>, <class '__main__.Rectangle'>,
<class 'object'>)

```

그러니... 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/)
118 changes: 117 additions & 1 deletion _posts/2023-01-06-signleton-python.markdown
Original file line number Diff line number Diff line change
@@ -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/

0 comments on commit 28a41d7

Please sign in to comment.