티스토리 뷰

이 포스팅은 파이썬 3 기준으로 인스턴스 메소드에 대하여 이야기 합니다.

 

본 내용에 앞서 아래 2가지 용어를 먼저 짚고 넘어가는게 좋겠습니다.

- 인스턴스: 클래스의 생성자가 실행되어 얻어진 클래스 객체

- 인스턴스 메소드: 인스턴스에 바인딩된 함수

 

모든 인스턴스 메소드의 생김새는 일단 아래와 비슷하게 생겼죠

class MyClass:
  def my_method(self, *args, **kwargs):
    # some code comes here ...
    pass

클래스 하위에 소속 되어있고, 공통적으로 암묵적 첫번째 positional argument 인 self 를 가지고 있습니다.

여기서 self 는 인스턴스 자체를 가리킵니다.

즉, 모든 인스턴스 메소드는 인스턴스 정보에 대한 접근이 가능하며, 이를 이용한 각종 작업 수행이 가능하다는 얘기가 되겠지요.

 

그럼 Python의 이 인스턴스 메소드들 에게도 Public, Protected, Private 의 구분이 있을까요?

음. 답변부터 해드리면 암묵적으로는 있지만, 언어적으로는 없다 라고 할수 있겠네요.

자, 그럼 이제부터 종류별로 그 속성을 살펴보면서 왜 그런지 설명을 드리죠.

 

1. Public method

- 언더바가 없이 시작하는 메소드 

- 어디서나 호출이 가능한 공용 함수

- 하위 클래스 override 허용

- 일반적으로 작성되는 대부분의 메소드를 차지

2. Protected method

- 언더바 1개로 시작하는 메소드 

- 어디서나 호출이 가능하지만, 암묵적 규칙에 의해 본 클래스 내부와 하위클래스 에서만 호출해야 하는 함수

- 하위 클래스 override 허용

- 성숙한 파이썬 코더만이 제대로 사용가능한 함수

- 참고링크: https://stackoverflow.com/questions/11483366/protected-method-in-python

- 아래 Django 라이브러리에서 가져온 protected method override 샘플코드가 있으니 감상해보세요~

class StreamingHttpResponse(HttpResponseBase):
    """
    A streaming HTTP response class with an iterator as content.

    This should only be iterated once, when the response is streamed to the
    client. However, it can be appended to or replaced with a new iterator
    that wraps the original content (or yields entirely new content).
    """

    streaming = True

    def __init__(self, streaming_content=(), *args, **kwargs):
        super(StreamingHttpResponse, self).__init__(*args, **kwargs)
        # `streaming_content` should be an iterable of bytestrings.
        # See the `streaming_content` property methods.
        self.streaming_content = streaming_content

    @property
    def content(self):
        raise AttributeError(
            "This %s instance has no `content` attribute. Use "
            "`streaming_content` instead." % self.__class__.__name__
        )

    @property
    def streaming_content(self):
        return map(self.make_bytes, self._iterator)

    @streaming_content.setter
    def streaming_content(self, value):
        self._set_streaming_content(value)

    def _set_streaming_content(self, value):
        # Ensure we can never iterate on "value" more than once.
        self._iterator = iter(value)
        if hasattr(value, 'close'):
            self._closable_objects.append(value)

    def __iter__(self):
        return self.streaming_content

    def getvalue(self):
        return b''.join(self.streaming_content)


class FileResponse(StreamingHttpResponse):
    """
    A streaming HTTP response class optimized for files.
    """
    block_size = 4096

    def _set_streaming_content(self, value):
        if hasattr(value, 'read'):
            self.file_to_stream = value
            filelike = value
            if hasattr(filelike, 'close'):
                self._closable_objects.append(filelike)
            value = iter(lambda: filelike.read(self.block_size), b'')
        else:
            self.file_to_stream = None
        super(FileResponse, self)._set_streaming_content(value)

3. Private method 

- 언더바 2개로 시작하는 메소드 

- 본 클래스 내부에서만 사용이 가능

- 하위클래스 상속 및 호출이 불가능 (오류남)

- 외부 호출이 불가능 (오류남)

- 실제로 많이 쓰이지는 않는것으로 보임

 

-----

이제 조금 의문이 풀리셨나요?

protected 메소드의 경우, 암묵적 rule 이 있기 때문에 위와같이 말씀을 드렸던 것입니다.

실제로 라이브러리 코드들을 보면 protected method 를 외부에서 호출하는 경우는 없고요,

간혹 가다가 protected instance variable (self._some_var) 를 접근하는 경우는 있습니다. (only 조회 목적으로)

 

위에서 설명한 것들을 간단하게 코드로 구현해 보았으니

실제 동작이 궁금하신 분들은 아래 코드를 복붙하여 실행해보세요~

 

class Person:
    name = None

    def __init__(self, name):  # constructor
        self.name = name

    def __get_trailing_text(self):  # private method
        return "Nice to meet you !!!"

    def _hello(self):  # protected method
        return "Hello {}, {}".format( self.name, self.__get_trailing_text() )

    def hello(self):  # public method
        print(self._hello())


class Man(Person):
    def _hello(self):
        # self.__get_trailing_text() 사용 불가
        return "Hello Mr.{}".format(self.name)

p = Person("mark")
p.hello()  # Hello mark, Nice to meet you !!!

try:
    p.__get_trailing_text()
except Exception as e:
    print(e)  # AttributeError

m = Man("silva")
m.hello()  # Hello Mr.silva

# 가능은 하지만 좋지 않은 용법
m._hello()  # Hello Mr.silva

try:
    m.__get_trailing_text()  
except Exception as e:
    print(e)  # AttributeError

 

- END - 

댓글