Google Python Style Guide (Korean)
  • Introduction
  • 1 배경
  • 2 파이썬 언어 규칙
Powered by GitBook
On this page
  • 2.1 Lint
  • 2.1.1 정의
  • 2.1.2 장점
  • 2.1.3 단점
  • 2.1.4 결정
  • 2.2 Imports
  • 2.2.1 정의
  • 2.2.2 장점
  • 2.2.3 단점
  • 2.2.4 결정
  • 2.3 Packages
  • 2.3.1 장점
  • 2.3.2 단점
  • 2.3.3 결정
  • 2.4 Exception
  • 2.4.1 정의
  • 2.4.2 장점
  • 2.4.3 단점
  • 2.4.4 결정
  • 2.5 Global variables
  • 2.5.1 정의
  • 2.5.2 장점
  • 2.5.3 단점
  • 2.5.4 결정
  • 2.6 Nested/Local/Inner Classes and Functions
  • 2.6.1 정의
  • 2.6.2 장점
  • 2.6.3 단점
  • 2.6.4 결정
  • 2.7 Comprehensions & Generator Expressions
  • 2.7.1 정의
  • 2.7.2 장점
  • 2.7.3 단점
  • 2.7.4 결정
  • 2.8 Default Iterators and Operators
  • 2.8.1 정의
  • 2.8.2 장점
  • 2.8.3 단점
  • 2.8.4 결정
  • 2.9 Generators
  • 2.9.1 정의
  • 2.9.2 장점
  • 2.9.3 단점
  • 2.9.4 결정
  • 2.10 Lambda Function
  • 2.10.1 정의
  • 2.10.2 장점
  • 2.10.3 단점
  • 2.10.4 결정
  • 2.11 Conditional Expressions
  • 2.11.1 정의
  • 2.11.2 장점
  • 2.11.3 단점
  • 2.11.4 결정

Was this helpful?

2 파이썬 언어 규칙

2.1 Lint

여러분의 코드에 pylint를 사용하세요.

2.1.1 정의

pylint는 파이썬 소스코드의 버그와 스타일 문제점을 찾는 툴입니다. 일반적으로 C나 C++와 같은 조금 덜 동적인 언어의 컴파일러에 의해 발견되는 문제점을 잡아냅니다. 파이썬의 동적인 특성 때문에, 몇몇 경고들은 부정확할 수 있습니다; 하지만, 이러한 거짓 경고는 매우 드물게 나타날 것입니다.

2.1.2 장점

오타, 변수를 할당하기 전 사용 등 놓치기 쉬운 부분들을 잡아냅니다.

2.1.3 단점

pylint는 완벽하지 않습니다. 장점을 활용하기 위해선, 우리는 이를 때때로 1) 사용하고 2) 경고를 억제하거나 3) 향상시켜야 합니다.

2.1.4 결정

여러분의 코드에 반드시 pylint를 사용하세요.

다른 이슈가 가려지지 않도록 경고가 적절하지 않다면 억제시키세요. 경고를 억제시키기 위해선, 여러분은 아래와 같이 한 줄 수준의 주석을 달면 됩니다.

dict = 'something awful'  # Bad Idea... pylint: disable=redefined-builtin

pylint 경고들은 각각 상징적인 이름(empty-docstring)으로 구글 특유의 경고는 g-로 시작합니다.

상징적인 이름이 경고 억제의 사유를 충분히 설명하지 못한다면, 설명문을 다세요.

이러한 방법의 경고 억제는 우리가 쉽게 다시 억제 대상을 찾을 수 있도록 해줍니다.

여러분은 이렇게 pylint의 경고 목록을 확인할 수 있습니다:

pylint --help-msg=C6409

옛 형식인 pylint: disable-msg 대신 pylint: disable를 사용하세요.

사용되지 않은 함수매개변수의 경고는 함수의 시작부에서 변수를 삭제함으로써 억제시킬 수 있습니다. 항상 왜 지우는지 주석을 다세요. "Unused."가 적당할 것입니다. 예를 들면:

def viking_cafe_order(spam, beans, eggs=None):
    del beans, eggs  # Unused by vikings.
    return spam + spam + spam

이와 같은 경고를 억제하기 위한 다른 일반적인 방법들에는 '_'를 사용되지 않는 함수매개변수의 식별자로 사용하기, 이름 앞에 'unused_'를 붙이기, 또는 '_'로 할당하기가 있습니다. 이러한 형식들은 더 이상 권장되지는 않습니다. 처음 두 break 호출자는 함수매개변수를 이름으로 전달하는 반면, 마지막은 그 함수매개변수가 실제로 사용되지 않는다고 강요하지 않습니다.

2.2 Imports

2.2.1 정의

한 모듈에서 다른 모듈로 코드를 공유하기 위한 재사용 매커니즘입니다.

2.2.2 장점

네임스페이스 관리 규약은 간단합니다. 각 식별자의 소스는 일관된 방식으로 표시됩니다. x.Obj은 객체 Obj가 x라는 모듈 안에 정의되어 있음을 의미합니다.

2.2.3 단점

모듈 이름이 여전히 충돌할 가능성이 있습니다. 일부 모듈 이름은 불편하게 깁니다.

2.2.4 결정

  • import x는 패키지나 모듈을 임포트할 때 사용하세요.

  • from x import y는 x가 패키지 접두사이고 y가 접두사가 없는 모듈 이름일 때 사용하세요.

  • from x import y as z는 y라는 이름을 가지고 있는 두 개의 모듈을 임포트해야 하거나 y가 불편할 정도로 길 때 사용하세요.

  • import y as z는 z가 표쥰 약어(예를 들어, numpy의 np)일 때만 사용하세요.

예를 들면 sound.effects.echo 모듈은 아래와 같이 임포트될 것입니다.

from sound.effects import echo
...
echo.EchoFilter(input, output, delay=0.7, atten=4)

임포트를 할 때는 상대적인 이름을 사용하지 마세요. 모듈이 동일한 패키지에 있더라도 전체 패키지 이름을 사용하세요. 이렇게 하면 의도하지 않게 패키지를 두 번 임포트하는 것을 방지할 수 있습니다.

2.3 Packages

모듈의 전체 경로를 이용해서 각 모듈을 임포트하세요.

2.3.1 장점

제작자가 의도하지 않은 방법으로 모듈 경로를 지정하는 것으로 발생할 수 있는 모듈 이름의 충돌이나 부정확한 모듈 경로를 임포트 하는 것을 방지합니다.

2.3.2 단점

패키지 계층 구조를 복제해야 하기 때문에 코드를 전개하기 더 힘들어집니다. 현대 전개 매커니즘에서 별 문제는 압니다.

2.3.3 결정

모든 코드에서 각 모듈은 전체 패키지의 이름으로 임포트해야 합니다.

임포트는 아래와 같아야 합니다:

예:

# Reference absl.flags in code with the complete name (verbose).
import absl.flags
from doctor.who import jodie

FLAGS = absl.flags.FLAGS
# Reference flags in code with just the module name (common).
from absl import flags
from doctor.who import jodie

FLAGS = flags.FLAGS

아니오: (이 파일이 jodie.py 파일도 함께 있는 doctor/who에 있다고 가정합니다)

# Unclear what module the author wanted and what will be imported.  The actual
# import behavior depends on external factors controlling sys.path.
# Which possible jodie module did the author intend to import?
import jodie

메인 바이너리가 위치하고 있는 디렉토리가 일부 환경에서 그렇다 하더라도 sys.path 경로 안에 있다고 가정하면 안 됩니다. 이런 경우, import jodie가 써드파티나 최상위 패키지의 jodie를 나타내는 것으로 가정해야 합니다, 로컬에 있는 jodie.py가 아닙니다.

2.4 Exception

예외처리는 허용되지만 조심히 사용해야 합니다.

2.4.1 정의

예외처리는 에러나 다른 예외적인 상황을 다루기 위해 코드 블록의 정상적인 컨트롤 플로우를 벗어나는 것을 의미합니다.

2.4.2 장점

정상적인 코드의 컨트롤 플로우는 에러 취급 코드로 인해 어수선하지 않습니다. 특정 상황이 발생하면 다수의 프레임을 컨트롤 플로우가 건너뛰도록 허용도 합니다, 예를 들어, N 번 중첩된 함수에서 에러 코드를 전달하지 않고 한 스텝에 반환하기.

2.4.3 단점

컨트롤 플로우의 혼란을 야기할 수 있습니다. 라이브러리를 콜 할 때 에러 케이스들을 놓치기 쉽습니다.

2.4.4 결정

예외처리는 반드시 특정 상황에 따라서 사용되야 합니다:

  • 예외처리는 이렇게 일으키세요: raise MyError('Error message') 또는 raise MyError().

  • 두 개의 매개변수를 사용하는 형식(raise MyError, 'Error message')을 사용하지 마세요.

이치에 맞게 내장 예외처리 클래스를 사용하세요. 예를 들면, 여러분이 음수를 전달했지만 양수를 기대했을 때는 ValueError를 일으키세요. 공용 API 매개변수 값의 유효성 검사에서 assert 구문을 사용하지 마세요. assert는 내부적 정확성을 보장하기 위해 사용되며, 정확한 사용을 강요하거나 예상치 못한 이벤트가 발생했음을 나타내기 위해 사용되는 것이 아닙니다. 후자에서 예외처리가 필요한 경우, raise 구문을 사용하세요. 예를 들면:

Yes:
  def connect_to_next_port(self, minimum):
    """Connects to the next available port.

    Args:
      minimum: A port value greater or equal to 1024.
    Raises:
      ValueError: If the minimum port specified is less than 1024.
      ConnectionError: If no available port is found.
    Returns:
      The new minimum port.
    """
    if minimum < 1024:
      raise ValueError('Minimum port must be at least 1024, not %d.' % (minimum,))
    port = self._find_next_open_port(minimum)
    if not port:
      raise ConnectionError('Could not connect to service on %d or higher.' % (minimum,))
    assert port >= minimum, 'Unexpected port %d when minimum was %d.' % (port, minimum)
    return port
No:
  def connect_to_next_port(self, minimum):
    """Connects to the next available port.

    Args:
      minimum: A port value greater or equal to 1024.
    Returns:
      The new minimum port.
    """
    assert minimum >= 1024, 'Minimum port must be at least 1024.'
    port = self._find_next_open_port(minimum)
    assert port is not None
    return port
  • 라이브러리나 패키지는 스스로의 예외처리를 정의할 수 있습니다. 그러고자 할 때는 반드시 기존에 존재하는 예외처리 클래스로부터 상속을 받아야 합니다. 예외처리 이름은 Error로 끝나며 말을 더듬게 (foo.FooError) 하지 않아야 합니다.

  • 여러분이 예외처리를 다시 일으키려고 하거나 (에러 메세지 출력을) 쓰레드 가장 바깥쪽 코드 블록에서 하는게 아니라면, catch-all except 구문, 또는 catch Exception 또는 Standard Error를 절대 사용하지 마세요. 파이썬은 이런 관련 사항과 except:에 대해서는 매우 관대해서 잘못 스펠된 이름, sys.exit() 콜, Ctrl+C 방해, 뜻밖의 실패와 여러분이 잡고 싶지 않은 다른 모든 종류의 예외처리를 정말 다 잡아낼 것입니다.

  • try/except 블록 내 코드의 양을 최소화하세요. try의 바디가 크면 클수록, 코드 라인에 따라 의해 여러분이 예상하지 않은 예외처리를 일으킬 가능성이 커집니다. 그러한 경우, try/except 블록은 진짜 에러를 숨기게 됩니다.

  • try 블록에서 예외처리가 일어났든지 안 났든지 코드를 실행시키기 위해 finally 절을 사용하세요. 파일 닫기, 같은 정리에 자주 유용하게 사용됩니다.

  • 예외처리 값을 잡을 때, 콤마 대신에 as를 사용하세요. 예를 들면:

    try:
    raise Error()
    except Error as error:
    pass

2.5 Global variables

전역변수 사용을 피하세요.

2.5.1 정의

모듈 레벨에서나 클래스의 속성으로 선언된 변수.

2.5.2 장점

간혹 유용합니다.

2.5.3 단점

전역변수의 할당은 모듈이 처음 임포트될 때 완료되기 때문에, 임포트하는 동안 모듈의 동작을 바꿀 수 있습니다.

2.5.4 결정

전역변수의 사용을 피하세요.

2.6 Nested/Local/Inner Classes and Functions

중첩된 지역함수나 클래스가 지역변수로의 엑세스를 차단하는 용도로 사용된다면 괜찮습니다. 내부 클래스는 괜찮습니다.

2.6.1 정의

클래스는 메서드, 함수, 또는 클래스 안에서 정의될 수 있습니다. 함수는 메서드나 함수 안에서 정의될 수 있습니다. 중첩된 함수는 둘러싸인 스코프에서 정의된 변수에 읽기전용으로 엑세스할 수 있습니다.

2.6.2 장점

2.6.3 단점

중첩되거나 지역 클래스는 pickle로 다룰 수 없습니다. 중첩된 함수와 클래스는 직접적으로 테스트할 수 없습니다. 중첩은 여러분의 외부 함수를 더욱 길고 읽기 어렵게 만듭니다.

2.6.4 결정

이러한 것들은 몇 가지 주의사항으로 괜찮습니다. 지역 값으로의 엑세스를 차단하는 경우가 아니라면 중첩된 함수나 클래스의 사용을 피하세요. 함수를 모듈 사용자에게서 숨기기 위해 중첩시키지 마세요. 대신, 테스트에서 계속 엑세스할 수 있도록 모듈 레벨에서 이름 앞에 _를 붙이세요.

2.7 Comprehensions & Generator Expressions

간단한 경우에 사용하는 것은 괜찮습니다.

2.7.1 정의

리스트, 딕셔너리, 그리고 세트 컴프리헨션 및 제너레이터 표현식은 기존 루프, map(), filter(), 또는 lambda를 사용하지 않고 컨테이너 타입이나 이리테이터를 만들 수 있는 간결하고 효율적인 방법을 제공합니다.

2.7.2 장점

간단한 컴프리헨션은 다른 딕셔너리, 리스트, 또는 세트 생성 테크닉보다 명확하고 간단할 수 있습니다. 제너레이터 표현식은 리스트 생성을 완전히 피해가기 때문에, 매우 효율적일 수 있습니다.

2.7.3 단점

복잡한 컴프리헨션이나 제너레이터 표현식은 읽기 어려울 수 있습니다.

2.7.4 결정

간단한 경우에 사용하는 것은 괜찮습니다. 각 부분은 한 줄: 매핑 표현식, for 절, 필터 표현식에 적합해야 합니다. 다수의 for 절 또는 필터 표현식은 허용되지 않습니다. 더 복잡해지는 경우엔 대신 루프를 사용하세요.

Yes:
  result = [mapping_expr for value in iterable if filter_expr]

  result = [{'key': value} for value in iterable
            if a_long_filter_expression(value)]

  result = [complicated_transform(x)
            for x in iterable if predicate(x)]

  descriptive_name = [
      transform({'key': key, 'value': value}, color='black')
      for key, value in generate_iterable(some_input)
      if complicated_condition_is_met(key, value)
  ]

  result = []
  for x in range(10):
      for y in range(5):
          if x * y > 10:
              result.append((x, y))

  return {x: complicated_transform(x)
          for x in long_generator_function(parameter)
          if x is not None}

  squares_generator = (x**2 for x in range(10))

  unique_names = {user.name for user in users if user is not None}

  eat(jelly_bean for jelly_bean in jelly_beans
      if jelly_bean.color == 'black')
No:
  result = [complicated_transform(
                x, some_argument=x+1)
            for x in iterable if predicate(x)]

  result = [(x, y) for x in range(10) for y in range(5) if x * y > 10]

  return ((x, y, z)
          for x in xrange(5)
          for y in xrange(5)
          if x != y
          for z in xrange(5)
          if y != z)

2.8 Default Iterators and Operators

리스트, 딕셔너리, 그리고 파일과 같이 기본 이터레이터나 연산자를 지원하는 타입에 이 것들을 사용하세요.

2.8.1 정의

딕셔너리와 리스트 같은, 컨테이너 타입들은, 기본 이터레이터와 멤버쉽 테스트 연산자(“in” and “not in”)를 정의합니다.

2.8.2 장점

기본 이터레이터와 연산자는 단순하고 효율적입니다. 별도의 메소드를 콜하지 않고도, 연산을 직접 표현합니다. 기본 연산자를 사용는 함수는 제네릭입니다. 연산을 지원하는 어떤 타입과도 사용될 수 있습니다.

2.8.3 단점

메소드의 이름(예를 들어, has_key()는 딕셔너리를 의미합니다)을 읽어서는 객체의 타입을 말할 수 없습니다. 이것도 장점입니다.

2.8.4 결정

리스트, 딕셔너리, 그리고 파일과 같이 기본 이터레이터나 연산자를 지원하는 타입에 이 것들을 사용하세요. 빌트-인 타입도 이터레이터 메소드를 정의합니다. 리스트를 반환하는 메소드에 이러한 방법을 선호합니다. 단, 반복하는 동안 컨테이너를 변경해서는 안 됩니다. 필요한 경우가 아니라면 절대 dict.iter*()와 같은 Python 2 특정 반복 메소드를 사용하지 마세요.

Yes:  for key in adict: ...
      if key not in adict: ...
      if obj in alist: ...
      for line in afile: ...
      for k, v in adict.items(): ...
      for k, v in six.iteritems(adict): ...
No:   for key in adict.keys(): ...
      if not adict.has_key(key): ...
      for line in afile.readlines(): ...
      for k, v in dict.iteritems(): ...

2.9 Generators

필요에 띠리 제너레이터를 사용하세요.

2.9.1 정의

제너레이터 함수는 매번 yield 구문을 실행할 때 마다 값을 산출하는 이터레이터를 반환합니다. 값을 산출하면, 다음 값이 필요할 때까지 제너레이터 함수의 런타임 상태는 일시 중단됩니다.

2.9.2 장점

더 간단한 코드입니다, 왜냐하면 각 콜에 대해 로컬 변수와 컨트롤 플로우의 상태가 유지되기 때문입니다. 제너레이터는 전체 값 목록을 한 번에 생성하는 함수보다 적은 메모리를 사용합니다.

2.9.3 단점

없습니다.

2.9.4 결정

좋습니다. 제너레이터 함수의 독스트링에서 "Return:" 대신 "Yield:"를 사용하세요.

2.10 Lambda Function

한 줄 용도로는 괜찮습니다.

2.10.1 정의

Lambda는 구문과는 반대로 표현식으로 익명 함수를 정의합니다. map()와 filter() 같은 고차 함수의 콜백이나 연산자를 정의하는데 자주 사용됩니다.

2.10.2 장점

편리합니다.

2.10.3 단점

지역함수보다 읽고 디버깅하기가 어렵습니다. 이름이 없다는 것은 스택 추적을 이해하기 더 어렵다는 것을 의미합니다. 함수가 표현식만을 포함하여야 하기 때문에 표현력이 제한됩니다.

2.10.4 결정

곱셈과 같은 일반적인 연산에서는, lambda 함수 대신에 operator 모듈의 함수를 사용하세요. 예를 들면, lambda x, y: x * y 대신 operator.mul를 사용하세요.

2.11 Conditional Expressions

2.11.1 정의

2.11.2 장점

2.11.3 단점

2.11.4 결정

Previous1 배경

Last updated 6 years ago

Was this helpful?

개별적인 클래스나 함수가 아닌, 패키지와 모듈을 다룰 때 import를 사용하세요. 로부터 임포트하는 것은 명시적으로 면제된다는 점에 유의하세요.

로부터의 임포트는 이 규칙에서 면제됩니다.

기술적으로 변수인 경우, 모듈 레벨의 상수는 허용되고 권장됩니다. 예를 들면: MAX_HOLY_HANDGRENADE_COUNT = 3. 상수의 이름은 모두 대문자를 사용하고 언더스코어를 사용하여야 합니다. 아래의 을 참고하세요.

필요한 경우, 전역변수는 모듈 레벨에서 선언하고 이름에 _을 추가하여 모듈 내부 변수로 만들어야 합니다. 외부 접근은 공용 모듈 레벨의 함수를 통해 이루어져야 합니다. 아래의 을 참고하세요.

매우 제한된 범위의 내부에서만 사용되는 유틸리티 클래스와 함수를 정의할 수 있게 합니다. 매우 -y입니다. 일반적으로 데코레이터를 구현하는데 사용됩니다.

한 줄 용도로는 괜찮습니다. 만약 lambda 함수 안의 코드가 60-80 자보다 많다면, 일반적인 를 사용하는 것이 더 좋을 것입니다.

typing 모듈
타이핑 모듈
Naming
Naming
ADT
중첩 함수