정적 메서드, 클래스 메서드
-
메서드의 확장 형태로
정적 메서드
와클래스 메서드
가 있다. -
정적 메서드
는인스턴스 객체
를 통하지 않고클래스
를 통해직접
호출할 수 있는 메서드이다. -
이 경우 메서드를 정의할 때 인스턴스 객체를 참조하는
self
라는 인자를 선언하지 않는다. -
클래스 메서드
는 암묵적으로 첫 인자로 클래스 객체가 전달된다.
< 호출할 메서드 이름 > = staticmethod( 클래스 내에 정의한 메서드 이름 )
< 호출할 메서드 이름 > = classmethod( 클래스 내에 정의한 메서드 이름 )
-
예를 들어 클래스부터 생성되는 인스턴스의 개수를 관리하고 싶은 경우
클래스 영역에서 해당 정보를 관리하는 것이 가장 효율적일 것이다.
-
이러한 정보가 저장/출력될 수 있게 다음과 같이 클래스를 정의했다.
class CounterManager:
insCount = 0
def __init__(self):
CounterManager.insCount += 1
def printInstanceCount():
print("Instance Count : ", CounterManager.insCount)
a, b, c = CounterManager(), CounterManager(), CounterManager()
CounterManager.printInstanceCount()
b.printInstanceCount() # 암묵적으로 인스턴스 객체를 받기 때문에 Error가 발생
Instance Count : 3
Traceback (most recent call last):
File "/Users/gy8971/Desktop/gid/1.Programming/Python/init.py", line 12, in <module>
b.printInstanceCount() # 암묵적으로 인스턴스 객체를 받기 때문에 Error가 발생
TypeError: printInstanceCount() takes 0 positional arguments but 1 was given
-
인스턴스 영역의 값을 참조하지 않기 때문에
메서드를 정의할 때 첫 인자로 암묵적으로 받는
인스턴스 객체(self)
는 사용하지 않았다. -
그 결과 클래스를 통해 호출되는 경우는 정상적으로 수행
-
인스턴스 객체를 이용해 호출하는 경우에는
TypeError
가 발생 -
위와 같은 Error가 발생하지 않게 정적/클래스 메서드를 이용해 다음과 같이 작성할 수 있다.
class CounterManager:
insCount = 0
def __init__(self):
CounterManager.insCount += 1
def staticPrintCount():
print("Instance Count : ", CounterManager.insCount)
SprintCount = staticmethod(staticPrintCount) # 정적 메서드로 등록
def classPrintCount(cls): # 클래스 메서드 정의(암묵적으로 첫 인자는 클래스를 받음)
print("Instance Count : ", cls.insCount)
CprintCount = classmethod(classPrintCount) # 클래스 메서드로 등록
a, b, c = CounterManager(), CounterManager(), CounterManager()
CounterManager.SprintCount()
b.SprintCount()
CounterManager.CprintCount()
b.CprintCount()
Instance Count : 3
Instance Count : 3
Instance Count : 3
Instance Count : 3
-
파이썬에서는 기본적으로
public
속성을 갖기 때문에다음과 같이 클래스의 외부에서 접근/변경이 가능하다.
print(CounterManager.insCount) # 클래스 외부에서 변수에 접근하는 경우
CounterManager.insCount = 0 # 클래스 외부에서 변수에 값을 변경하는 경우
-
파이썬에서는
이름 변경(Naming Mangling)
으로 문제를 해결했다. -
즉 클래스 내의 멤버 변수나 함수를 정의할 때
이름이
__
로 시작하는 경우 클래스 외부에서 참조할 때자동적으로
_[클래스 이름]__[멤버 이름]
으로 변경된다. -
물론 클래스 내에서는 정의한 이름인
__[멤버이름]
만으로 사용할 수 있다.
class CounterManager:
__insCount = 0 # 이름 변경을 위해 '__'를 변수명 앞에 사용
def __init__(self):
CounterManager.__insCount += 1
def staticPrintCount():
print("Instance Count : ", CounterManager.__insCount) # 클래스 내부에서 사용했을때 선언한 이름과 동일하게 사용 가능
SprintCount = staticmethod(staticPrintCount)
a, b, c = CounterManager(), CounterManager(), CounterManager()
CounterManager.SprintCount()
-
이렇게 이름 변경이 적용된 멤버 변수에 그 이름을 사용해 외부에서 접근하는 경우
클래스 내에 동일한 이름이 없다는
NameError
가 발생한다. -
물론
변경된 이름
으로접근
하는 경우(_CounterManager__insCount) 그 변수에 대한읽기/쓰기
가 가능하다. -
즉 파이썬에서는 문법의 제약사항으로 정보 은닉 기능을 제공하기보다는 이름 변경으로 개발자의 의도를 나타내게 했다.