Gidhub BE Developer

정적 메서드, 클래스 메서드

2018-02-06
goodGid

정적 메서드, 클래스 메서드

  • 메서드의 확장 형태로 정적 메서드클래스 메서드가 있다.

  • 정적 메서드인스턴스 객체를 통하지 않고 클래스를 통해 직접 호출할 수 있는 메서드이다.

  • 이 경우 메서드를 정의할 때 인스턴스 객체를 참조하는 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) 그 변수에 대한 읽기/쓰기가 가능하다.

  • 즉 파이썬에서는 문법의 제약사항으로 정보 은닉 기능을 제공하기보다는 이름 변경으로 개발자의 의도를 나타내게 했다.


Recommend

Index