Deep Dive super() in python
어느 언어에서든 super 는 상속하는 parent class 를 가져오는 keyword 다. single inheritance 인 경우밖에 없다면 이 문서를 작성할 필요도 없었을텐데, 복잡한 인자를 사용한 경우를 만났는지 링크를 남겨두었고, 미래의 내가 문서를 작성하고 있다.
bound/unbound method
- bound method
- 어떤 클래스에 속해있는 메소드
- unbound method
- class instance 를 인자로 받지 않는 메소드
- 파이선 3으로 올라오면서 사라진 개념임
- instance 를 받지 않는 것은 static_method 로서 만들수는 있음.
# 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 를 사용하고 싶은 경우 아래와 같이 사용할 수 있다.
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 를 우선적으로 탐색해서 가져올지 알려준다.
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 를 우선적으로 볼 것이다.
>>> RightPyramid.__mro__
(<class '__main__.RightPyramid'>, <class '__main__.Triangle'>,
<class '__main__.Square'>, <class '__main__.Rectangle'>,
<class 'object'>)
그러니… mro 에 의존할 것이 아니고 super 를 사용할 때 사용할 class 를 명시하는 게 권장될 것 같다.