Skip to content

Latest commit

 

History

History
322 lines (240 loc) · 15.2 KB

File metadata and controls

322 lines (240 loc) · 15.2 KB

3.8 Comments and Docstrings

  • 모듈, 함수, 메소드에 올바른 형식의 docstring과 인라인 주석을 사용하세요.

3.8.1 Docstrings

  • 파이썬은 코드를 문서화 할 때 docstring 을 사용합니다.
  • docstring 은 패키지, 모듈, 클래스나 함수의 첫번째 선언되는 문자열입니다.
  • 이 문자열은 pydoc 이 사용하는 __doc__ 멤버 오브젝트에서 자동으로 추출될 수 있습니다. (여러분의 모듈에서 pydoc 를 실행 후 결과를 확인해보세요)
  • PEP257 에 따라 docstring 을 시작하거나 끝낼 때는 """ 를 사용하세요.
  • docstring은 마침표, 물음표, 느낌표로 끝나는 요약줄(한 줄)로 시작하여야 하며 한 줄의 공백을 두고 내용을 담고있는 나머지 docstring 이 이어져야 합니다.
  • 또한 내용을 담고있는 docstring 은 """ 와 같은 커서위치에서 시작하여야 합니다.

3.8.2 Modules

  • 프로젝트에 알맞는 라이센스 보일러 플레이트를 선택하세요. (예를 들면, Apache 2.0, BSD, LGPL, GPL)

  • 모든 파일은 라이센스 보일러 플레이트를 가지고 있어야 합니다.

    """모듈이나 프로그램에 대한 한 줄 요약으로, 마침표로 끝나야 합니다.
    
    한 줄을 비워두세요. 이 docstring의 나머지 부분에는 모듈이나 프로그램에
    대한 전반적인 설명이 포함되어야 합니다. 선택적으로, 내보낸 클래스와
    함수에 대한 간단한 설명 및/또는 사용 예시도 포함될 수 있습니다.
    
    전형적인 사용 예시:
    
      foo = ClassFoo()
      bar = foo.FunctionBar()
    """

3.8.2.1 Test modules
  • 테스트 파일의 모듈 수준 docstring은 필수는 아닙니다.
  • 추가적인 정보를 제공할 필요가 있는 경우에만 포함해야 합니다.
  • 예를 들면, 테스트를 실행하는 방법에 대한 구체적인 내용, 특이한 설정 패턴에 대한 설명, 외부 환경에 대한 의존성 등이 포함될 수 있습니다.
"""이 Blaze 테스트는 golden 파일을 사용합니다.
`google3` 디렉토리에서
`blaze run //foo/bar:foo_test -- --update_golden_files` 명령어를 실행하여
이러한 파일을 업데이트할 수 있습니다.
"""
  • 새로운 정보를 제공하지 않는 docstring은 사용하지 말아야 합니다.
"""Tests for foo.bar."""

3.8.3 Functions and Methods

  • 이 섹션에서 ‘function’은 메소드, 함수, 제너레이터 또는 속성을 의미합니다.

  • 다음 중 하나 이상의 속성을 가진 모든 함수에는 docstring이 필수입니다.

    • 공개 API의 일부인 경우
    • 비교적 큰 경우
    • 직관적이지 않은 로직을 가진 경우
  • docstring은 함수의 코드를 읽지 않고도 함수 호출을 작성할 수 있을 만큼 충분한 정보를 제공해야 합니다.

  • docstring은 함수의 호출 구문과 의미를 설명해야 하며, 일반적으로 구현 세부 사항은 포함하지 않아야 하지만, 이러한 세부 사항이 함수 사용 방법에 중요하다면 예외입니다.

  • 예를 들어, 인자를 사이드 임펙트로 변경하는 함수는 그 점을 docstring에 명시해야 합니다.

  • 그렇지 않으면, 호출자에게 중요하지 않은 함수 구현의 미묘하지만 중요한 세부 사항은 함수의 docstring보다는 코드 옆에 주석으로 표현하는 것이 좋습니다.

  • docstring은 서술형("""Fetches rows from a Bigtable.""") 또는 명령형("""Fetch rows from a Bigtable.""") 스타일일 수 있지만, 파일 내에서 스타일은 일관되게 유지해야 합니다.

  • @property 속성의 docstring은 속성이나 함수 인자의 docstring과 같은 스타일을 사용해야 합니다 ("""The Bigtable path.""" 대신에 """Returns the Bigtable path.""").

  • 함수의 특정 측면은 아래에 나열된 특별한 섹션에서 문서화해야 합니다.

  • 각 섹션은 콜론으로 끝나는 제목 행으로 시작합니다.

  • 제목을 제외한 모든 섹션은 2칸 또는 4칸 공백의 걸쳐서 들여쓰기를 유지해야 합니다 (파일 내에서 일관되게 유지).

  • 함수의 이름과 시그니처가 충분히 정보를 제공하여 한 줄의 docstring으로 적절히 설명할 수 있는 경우, 이러한 섹션은 생략할 수 있습니다.

  • 매개변수를 각각 이름으로 나열합니다. 각 이름에는 설명문이 따르며 콜론 뒤에 공백이나 새로운 라인으로 분리되어야 합니다.
  • 만약 설명문이 너무 길어 한 줄인 80자를 초과할 경우 매개변수 이름보다 2칸 또는 4칸의 들여쓰기를 사용합니다.(파일의 나머지 문서(docstring)와 일치합니다.)
  • 만약 코드가 자료형에 대한 주석을 담고 있지 않다면 설명문은 요구되는 자료형을 포함해서 기록해야 합니다.
  • 함수가 *foo(가변길이의 매개변수 리스트) 또는 **bar(임의의 키워드 매개변수)를 받는다면 *foo**bar로 기록되어야 합니다.

  • 반환 값의 의미를 설명하고, 타입 어노테이션에서 제공하지 않는 타입 정보도 포함해야 합니다.
  • 함수가 None만 반환하는 경우, 이 섹션은 필요하지 않습니다.
  • docstring이 "Return", "Returns", "Yield", "Yields"로 시작하고(e.g. """Returns row from Bigtable as a tuple of strings."""), 첫 번째 문장이 반환 값을 설명하기에 충분할 경우, 이 섹션은 생략될 수 있습니다.
  • 이전의 'NumPy 스타일'을 모방하지 마세요. (example) 이 스타일은 종종 튜플 반환 값을 여러 개의 개별 반환 값처럼 각각의 이름으로 문서화했습니다. (튜플이라는 점을 언급하지 않고)
  • 대신, 반환 값을 다음과 같이 설명하세요: "Returns: A tuple (mat_a, mat_b), where mat_a is ..., and ...".
  • docstring에서 사용되는 설명용 이름은 함수 본문에서 사용되는 내부 이름과 반드시 일치할 필요는 없습니다 (내부 이름은 API의 일부가 아니기 때문입니다)
  • 함수가 yield를 사용하는 경우(즉, 제너레이터인 경우), Yields: 섹션에서는 호출 결과로 반환되는 제너레이터 객체가 아니라, next()에 의해 반환되는 객체를 문서화해야 합니다.

  • interface와 관련된 모든 예외를 설명 뒤에 나열합니다.

  • Args:에 설명된 것과 유사한 예외 이름 + 콜론 + 공백 또는 줄 바꿈과 hanging indent 스타일을 사용하세요.

  • 명시된 API가 docstring을 위반했을 될 경우, 예외를 문서화하지 않습니다. (왜냐하면 이것은 역설적으로 API의 API를 위반하는 행동을 만들 수 있기 때문이다.)

    def fetch_smalltable_rows(
        table_handle: smalltable.Table,
        keys: Sequence[bytes | str],
        require_all_keys: bool = False,
    ) -> Mapping[bytes, tuple[str, ...]]:
      """Fetches rows from a Smalltable.
    
      Retrieves rows pertaining to the given keys from the Table instance
      represented by table_handle.  String keys will be UTF-8 encoded.
    
      Args:
          table_handle: An open smalltable.Table instance.
          keys: A sequence of strings representing the key of each table
            row to fetch.  String keys will be UTF-8 encoded.
          require_all_keys: If True only rows with values set for all keys will be
            returned.
    
      Returns:
          A dict mapping keys to the corresponding table row data
          fetched. Each row is represented as a tuple of strings. For
          example:
    
          {b'Serak': ('Rigel VII', 'Preparer'),
          b'Zim': ('Irk', 'Invader'),
          b'Lrrr': ('Omicron Persei 8', 'Emperor')}
    
          Returned keys are always bytes.  If a key from the keys argument is
          missing from the dictionary, then that row was not found in the
          table (and require_all_keys must have been False).
    
      Raises:
          IOError: An error occurred accessing the smalltable.
      """
  • 마찬가지로, 줄 바꿈이 있는 Args:도 허용합니다.

    def fetch_smalltable_rows(
        table_handle: smalltable.Table,
        keys: Sequence[bytes | str],
        require_all_keys: bool = False,
    ) -> Mapping[bytes, tuple[str, ...]]:
        """Fetches rows from a Smalltable.
    
        Retrieves rows pertaining to the given keys from the Table instance
        represented by table_handle.  String keys will be UTF-8 encoded.
    
        Args:
          table_handle:
            An open smalltable.Table instance.
          keys:
            A sequence of strings representing the key of each table row to
            fetch.  String keys will be UTF-8 encoded.
          require_all_keys:
            If True only rows with values set for all keys will be returned.
    
        Returns:
          A dict mapping keys to the corresponding table row data
          fetched. Each row is represented as a tuple of strings. For
          example:
    
          {b'Serak': ('Rigel VII', 'Preparer'),
          b'Zim': ('Irk', 'Invader'),
          b'Lrrr': ('Omicron Persei 8', 'Emperor')}
    
          Returned keys are always bytes.  If a key from the keys argument is
          missing from the dictionary, then that row was not found in the
          table (and require_all_keys must have been False).
    
        Raises:
          IOError: An error occurred accessing the smalltable.
        """

3.8.3.1 Overridden Methods
  • 기본 클래스의 메서드를 오버라이드하는 메서드는 @override 데코레이터(typing_extensions 또는 typing 모듈에서 제공)를 명시적으로 사용하는 경우 docstring이 필요하지 않습니다.

  • 단, 오버라이딩된 메서드의 동작이 기본 메서드의 계약을 실질적으로 개선하거나, 추가적인 사이드 임펙트 등을 문서화해야 하는 경우에는, 그러한 차이점이 최소한 포함된 docstring이 오버라이딩 메서드에 필요합니다.

    from typing_extensions import override
    class Parent:
      def do_something(self):
        """Parent method, includes docstring."""
    # 자식 클래스, 오버라이드로 주석이 달린 메서드.
    class Child(Parent):
      @override
      def do_something(self):
        pass
    # 자식 클래스에서 @override 데코레이터가 없는 경우, docstring이 필요합니다.
    class Child(Parent):
      def do_something(self):
        pass
    # docstring이 단순한 경우, @override만으로도 문서가 기본 클래스에 있음을 표시할 수 있습니다.
    class Child(Parent):
      @override
      def do_something(self):
        """See base class."""

3.8.4 Classes

  • 클래스는 선언 바로 아래에 해당 클래스를 설명하는 docstring 를 가지고 있어야 합니다.
  • properties을 제외한 공개 속성은 Attributes 섹션에서 문서화해야 하며, 함수의 Args 섹션과 동일한 형식을 따라야 합니다.
class SampleClass:
    """Summary of class here.

    Longer class information...
    Longer class information...

    Attributes:
        likes_spam: A boolean indicating if we like SPAM or not.
        eggs: An integer count of the eggs we have laid.
    """

    def __init__(self, likes_spam: bool = False):
        """Initializes the instance based on spam preference.
        Args:
          likes_spam: Defines if instance exhibits this preference.
        """
        self.likes_spam = likes_spam
        self.eggs = 0

    @property
    def butter_sticks(self) -> int:
        """The number of butter sticks we have."""
  • 모든 클래스의 docstring은 클래스 인스턴스가 무엇을 나타내는지를 설명하는 한 줄 요약으로 시작해야 합니다. 이는 Exception의 서브클래스도 예외가 무엇을 나타내는지를 설명해야 하며, 발생할 수 있는 컨텍스트에 대해서는 설명하지 않아야 함을 의미합니다. 클래스의 docstring은 클래스가 클래스라는 등의 불필요한 정보를 반복해서는 안 됩니다.

  • 올바른 예

    class CheeseShopAddress:
      """The address of a cheese shop.
      ...
      """
    class OutOfCheeseError(Exception):
      """No more cheese is available."""
  • 부적절한 예

    class CheeseShopAddress:
      """Class that describes the address of a cheese shop.
      ...
      """
    class OutOfCheeseError(Exception):
      """Raised when no more cheese is available."""

3.8.5 Block and Inline Comments

  • 마지막으로 주석을 달아야 하는 곳은 코드의 복잡한 부분입니다.
  • 만약 추후 code review에서 코드를 설명하려고 한다면 지금 주석을 달아두어야 합니다.
  • 복잡한 동작은 시작하기 전에 몇 줄의 주석을 달아야 합니다.
  • 잘 알려져 있지 않는 부분은 끝에 주석을 달아야 합니다.
# We use a weighted dictionary search to find out where i is in
# the array.  We extrapolate position based on the largest num
# in the array and the array size and then do binary search to
# get the exact number.

if i & (i-1) == 0:  # True if i is 0 or a power of 2.
  • 가독성 향상을 위해 이러한 주석들은 코드에서 최소 2줄 떨어져 있어야 합니다.

  • 하지만 코드 자체를 설명하지는 마세요.

  • 코드를 읽고 있는 사람이 여러분보다 파이썬을 더 잘 알고 있다고 가정하세요. (물론 그게 중요한 것은 아닙니다.)

  • 부적절한 예(주석)

    # Now go through the b array and make sure whenever i occurs
    # the next element is i+1

3.8.6 Punctuation, Spelling and Grammar

  • 스펠링과 문법 그리고 구두점에 주의를 기울이세요. 잘 써진 주석이 읽기도 편합니다.

  • 주석은 마치 말하는 것처럼 자연스럽게 읽을 수 있어야 하며 영문 주석의 경우 올바른 대문자와 구두점이 필요합니다.

  • 대부분의 경우 조각난 문장보다 온전한 문장이 높은 가독성을 가집니다.

  • 코드 끝에 붙는 짧은 주석 등의 경우 다소 형식적이지 않아도 되지만, 전체적인 일관성을 맞추어야 합니다.

  • 코드 리뷰어가 세미콜론이 사용되어야 하는데 컴마를 사용했다고 지적하는 것은 불만스러울 수 있지만 소스코드가 높은 수준의 명료성과 가독성을 가지는것은 매우 중요합니다.

  • 올바른 구두점, 스펠링 그리고 문법은 이를 얻을 수 있도록 도와줍니다.