Type Hint
class를 만들때나 이외의 상황에서 type hint를 지정할 수 있다.
Type hint를 지키지 않는다고 Error가 생기거나 하는 기능적인 것은 없으며,
가독성에 유리 하기 때문에 사용을 권장한다.
class Courier(object):
def assign(self, name: str, address: str) -> str :
위 코드에서 변수에 :str, :int 형태로 넣을 수 있고, ->str , ->None 형태로 결과 값에 대한 hint도 제공할 수 있다.
상속 (Inheritance)
기존 클래스를 활용하여 내용을 추가, 수정하기 위해서 사용한다.
기존의 class를 수정하거나 거기에 내용을 추가해도 되지만
기존 class의 형태를 유지하여야 하거나
수정이 허용되지 않는 상황,
혹은 기존 class가 라이브러리 형태로 제공되었을 경우 이러한 상속을 사용한다.
상속의 개념을 이해할 때,
엄밀히 말하면 상당한 차이가 있지만 개념적적으로 상속에 대해서 이해가 어렵다면
copy라는 관점에서 시작해서 차이점을 알아가는 것도 괜찮다.
기존에 class를 superclass라고 하고 상속을 받아 만들어진 class를 subclass라고 할 때,
superclass의 특성과 동작을 subclass가 복사하여 사용할 수 있도록 하고
subclass에서 해당 내용에 대해서 수정, 추가한다는 부분에서는
copy의 개념과 맞닿아 있지만,
다른 점을 보고자 한다면,
상속은 copy와는 다르게 상속 관계에 있는 클래스들 간에 계층 구조(hierarchy)를 형성한다.
이 계층 구조를 통해서 코드의 재사용과 확장성을 제공하며 이것이 OOP의 중요한 개념 중 하나 이기도 하다.
class subclass(superclass):
아래처럼 Python에서는 다중 상속을 지원한다.
class subclass(superclass1, superclass2):
이경우 죽음의 다이아몬드와 같은 문제가 발생할 수있다.
이문제를 python에서는 매서드 탐색 순서를 따르는 것으로 해결한다.
print(subclass.mro()) #MRO(Method Resolution Order)
위 코드로 매소드 탐색 순서를 알 수 있다.(하위에서 상위로)
파이썬은 다이아몬드 상속 구조에서 메서드를 검색할 때,
먼저 왼쪽에서 오른쪽으로 순서대로 검색하는 C3 선형화 알고리즘을 사용한다.
가급적 다중 상속을 하지 않는 것을 추천한다.
이는 위와 같은 문제 뿐만 아니라 가독성도 떨어트리면서 코드를 관리 하는데에 다양한 문제를 발생 시킬 수 있다.
Duck typing
class superclass:
def __init__(self, data1):
class subclass1(superclass):
def __init__(self, data1, data2):
super().__init__(data1):
self.data2=data2
def deliver:
print(car)
class subclass2(superclass):
def __init__(self, data1, data2):
super().__init__(data1):
self.data2=data2
def deliver:
print(bike)
man = subclass1()
girl = subclass2()
def how_deliver(who):
who.deliver()
위와같이 함수로 재정의해서 효율적인 호출을 하는 방법이다
super()
subclass가 superclass의 init정보를 활용하기 위해서 활용되며 아래와 같이 사용된다.
super().__init__()
super().__init__(**kwargs)
여기서 **kwargs은 가변 키워드 인자(variable keyword arguments)를 받을 수 있는 키워드이다.
**kwargs를 호출 시 키워드 인자를 딕셔너리 형태로 받아들이고 호출 시 필요한 만큼의 키워드인자를 전달할 수 있게 된다.
때문에 **kwargs를 호출하면 유연하게 키워드 인자를 전달할 수 있다며, 함수나 method 내부에서 이를 활용할 수 있다.
만약 **Kwargs를 사용하지 않는다면
def func(a, b)와 같이 정의된 함수 func는 a와 b라는 두 개의 인자만을 받을 수 있다.
그렇기 때문에 superclass의 __init__() 메서드에 argument가 있다면 subclass의 __init__()에 **kwarge를 사용해주어야 한다.
만약 **kwargs를 써야 하는 상황에서 그러하지 않았다면 아래와 같은 에러코드가 발생한다.
__init__() missing required positional arguments
class subclass(superclass):
def __init__():
super().__init__()
__init__()
Class 내에서 사용될 변수들을 미리 지정해 놓는다.
python에서는 __init__ 함수가 첫 번째 변수로 무조건 해당 클래스 스스로를 받도록 설정되어 있다.
#pytorch code
class Net(nn.Module):
def __init__(self):
super().__init__()
self.fc1 = nn.Linear(28*28*1, 512)
self.fc2 = nn.Linear(512, 128)
self.fc3 = nn.Linear(128,10)
self.relu = nn.ReLU()
self.softmax = nn.Softmax(dim=1)
__init__() method의 장점
- 인스턴스 생성 시 초기화 작업을 수행할 수 있다.
- 인스턴스마다 다른 속성 값을 가질 수 있다.
- 인스턴스의 속성을 설정하는 데 유용하다.
- 객체 지향 프로그래밍의 주요 개념 중 하나인 생성자(constructor) 역할을 한다.
- 인스턴스를 생성할 때마다 호출되므로, 인스턴스의 초기화에 필요한 로직을 담을 수 있다.
__init__() method의 단점
- 인스턴스 생성 시마다 호출되므로, 불필요한 초기화 작업이 있다면 오버헤드가 발생할 수 있습니다.
- 인스턴스에 속성을 추가하거나 수정하는 작업만 수행할 수 있습니다. 클래스 자체와 관련된 작업은 수행할 수 없다.
self
첫 번째로 들어가는 변수명은 class스스로를 지칭하게 된다.
굳이 self를 사용하지 않아도 되지만 개발자 간의 코드 가독성을 높이기 위해서
관례적으로 공식문서의 self를 인용하는 편이다.
class Calc:
def __init__(self, a, b):
self.x = a
self.y = b
def plus(self):
return self.x + self.y
def minus(self):
return self.x - self.y
MLP를 예로들면
model = Net()이라고 했을때,
Net()은 Net.__init__(self)을 부른것과 같고 여기서 self는 model을 지칭하는것이므로 실제로
Net.__init__(model)과 같다고 볼 수 있다.
classmethod
python의 class 내에서 정의되는 특수한 종류의 method.
class 상태를 변경하거나 class수준의 작업을 수행하는 데 사용된다.
인스턴스를 생성하지 않고도 호출 할 수 있으므로, 편리하게 class기능을 사용할 수 있고,
class method 내부에서는 인스턴스 속성에 직접 접근할 수 없기 때문에 class method 내에 발생하는 부작용을 줄일 수 있다.
class Calc:
@classmethod
def plus(cls, a, b):
return a + b
@classmethod
def minus(cls, a, b):
return a - b
단점으로는
class mrthod 내부에서는 인스턴스 속성에 직접 접근할 수 없기 때문에, 인스턴스 속성을 활용한 작업을 수행할 수 없다.
그리고
클래스 자체에 속하는 기능만을 제공하므로, 인스턴스의 개별 상태에 따라 다르게 동작하는 기능은 class method로는 구현하기 어렵다.
@classmethod 라는 decorator를 사용하는 것이 관례이다.
class Circle:
pi = 3.14159
radius = 0
def __init__(self, radius):
self.radius = radius
@classmethod
def from_diameter(cls, diameter):
radius = diameter / 2
return cls(radius)
def calculate_area(self):
return self.pi * self.radius ** 2
# 클래스 메서드를 사용하여 직경을 입력받아 Circle 인스턴스 생성
circle = Circle.from_diameter(10)
print(circle.calculate_area()) # 출력: 78.53975
staticmethod( 정적 메서드)
staticmethod는 class나 인스턴스와 관련된 데이터나 동작을 수행하지 않는 독립적인 기능을 제공하는 데 사용된다.
class의 인스턴스와는 상호작용하지 않고, 단순히 클래스 네임스페이스 내에서 독립적으로 동작하는 함수와 유사한 역할을 한다.
때문에 class.__init__()에서 1개의 data만 받는다 하더라도 staticmethod에서는 독립적으로 2개 이상의 값을 받을 수 있다.
@staticmethod
def minus(a, b):
return a - b
class MathUtils:
@staticmethod
def add_numbers(a, b):
return a + b
result = MathUtils.add_numbers(5, 10)
print(result) # 출력: 15
'programming language > Python' 카테고리의 다른 글
[Python] any() (0) | 2023.08.22 |
---|---|
[Python] enumerate 함수 (0) | 2023.07.24 |
[Python] conditional expression, list comprehension (0) | 2023.07.18 |
[Python] 연산관련 function과 method (0) | 2023.07.18 |
[Python] lambda (0) | 2023.07.18 |