[Python] 스타일 가이드 : PEP8

Poke·2024년 3월 26일
post-thumbnail

PEP8(Python Enhancement Proposal)

Python 코드 작성시 따라야할 스타일 가이드 8가지

주요 가이드라인 요약

  1. 들여쓰기 : 4개의 Spaces 사용
  2. 한 줄의 최대 길이 : 최대 79자
  3. 메소드/클래스 간 공백 : 최상위 메소드와 클래스 사이에는 2줄의 빈줄 두기
  4. 메소드간 공백 : 클래스 내의 메소드 사이에는 1줄의 빈줄 두기
  5. 변수명 및 함수명 : 소문자구분된스네이크케이스를 사용
  6. 클래스명 : 대문자로시작하는카멜케이스를 사용
  7. 연산자 주변 공백 : 대입(=), 비교(==, <, >), 계산(+, -, *, /)는 연산자 주변에 공백

참고사이트

1. A Foolish Consistency is the Hobgoblin of Little Minds

  • 가독성 향상 + 일관성 유지

2. Code Lay-out

들여쓰기(Indentation)
4개의 공백 사용. Continuation lines는 소괄호, 중괄호, 대괄호로 묶거나 hanging indent를 사용하여 정렬.

# 👍🏻 좋은예:
foo = long_function_name(var_one, var_two,
                         var_three, var_four)
def long_function_name(                        # 인자들을 구분하기 위해 4개의 공백 추가
        var_one, var_two, var_three,
        var_four):         
    print(var_one)

# Hanging indents should add a level.
foo = long_function_name(
    var_one, var_two,
    var_three, var_four)
# 첫번째 줄은 들여쓰기가 되어있지 않고
# 두번째 줄은 들여쓰기가 되어 있음. hanging indent.
# 이어지는 줄이라는것을 나타내기 위해 추가적인 들여쓰기를 사용하여 구분하기.

# 👎🏻 나쁜예:
foo = long_function_name(var_one, var_two,   	# 함수 인자를 여러 줄로 나누어 작성할때는 행의 맨 처음에 인자를 두지않고 개행을 한 후 시작. 
    var_three, var_four)

def long_function_name(							# 함수 인자를 여러 줄로 나누어 작성할때는 함수본문과 구분이 명확하게 하기 위해 추가 들여쓰기 필요.
    var_one, var_two, var_three,
    var_four):
    print(var_one)
# if문의 조건이 너무 길때
# if문 다음에 한칸 띄고 ()괄호를 이용해 여러 줄로 나눔. 두번째 줄은 첫번째 줄과 동일한 들여쓰기.
if (this_is_one_thing and
    that_is_another_thing):
    do_something()
# 조건문과 실행 블록 사이에 주석을 추가하여 추가적인 구분
if (this_is_one_thing and
    that_is_another_thing):
    # 주석 추가
    do_something()
# 조건문의 두번째줄에 추가적인 들여쓰기를 사용하여 첫번째 줄과 구분.
if (this_is_one_thing
        and that_is_another_thing):
    do_something()
# 여러줄의 소괄호/중괄호/대괄호
# 마지막 항목의 첫번째 비공백 문자 아래에 괄호를 위치시키는 방법.
my_list = [
    1, 2, 3,
    4, 5, 6,
    ]  # 4 아래에 괄호 위치
result = some_function_that_takes_arguments(
    'a', 'b', 'c',
    'd', 'e', 'f',
    )
# 다중 줄 구조를 시작하 그 줄의 첫번째 문자 아래에 괄호를 위치시키는 방법.
my_list = [
    1, 2, 3,
    4, 5, 6,
]   # m 아래에 괄호 위치
result = some_function_that_takes_arguments(
    'a', 'b', 'c',
    'd', 'e', 'f',
)

Tabs or Spaces?
Python에서는 Tab 대신 Spaces를 사용하는 것을 선호. 이미 Tab을 사용한 경우 일관되게 Tab 사용.
특히 python3의 경우, Tab과 Spaces 혼용 사용 불가.
Maximum Line Length
한 줄의 최대 길이를 최대 79자로 제한. docstring/comments는 72자로 제한.
Continuation lines의 경우, 소괄호/중괄호/대괄호에 넣거나 \ 사용.

with open('/path/to/some/file/you/want/to/read') as file_1, \
     open('/path/to/some/file/being/written', 'w') as file_2:
    file_2.write(file_1.read())

Should a Line Break Before or After a Binary Operator?
연산기호 전후 모두 줄바꿈 가능하나, 가독성울 위해 연산기호 전에 줄바꿈하기

income = (gross_wages
          + taxable_interest
          + (dividends - qualified_dividends)
          - ira_deduction
          - student_loan_interest)

Black Lines
가장 상위의 함수와 클래스 정의는 2줄의 빈공간
클래스 내의 메소드정의는 1줄의 빈공간
함수내의 빈줄은 가능한 자제. 논리적 부분을 표시하기 위해서 사용.
Source File Encoding
UTF-8 사용, ASCII 문자 사용
Imports

# 👍🏻 좋은예:
import os
import sys

from subprocess import Popen, PIPE

# 👎🏻 나쁜예:
import sys, os

imports는 항상 파일의 맨 위, 만약 모듈의 주석이나 docstring이 있다면 주석, docstring 바로 뒤에 위치하는 것이 좋음.

import의 순서
1. 표준 라이브러리. 내장(설치없이 사용할 수 있는) 라이브러리 임포트
2. 외부에서 설치해야하는 패키지. 표준 라이브러리와 분리하여 위치시킴.
3. 로컬 애플리케이션/라이브러리 특정 import(프로젝트내 다른 모듈이나 사용자 정의 라이브러리)

# 👍🏻 좋은예:
# Module docstring
"""Example module to demonstrate proper import order."""

import os									# 표준 라이브러리
import sys

import requests								# 외부 라이브러리

from myapp import local_module				# 사용자 정의 라이브러리

절대 임포트 : 모듈의 전체 경로를 사용하여 해당 모듈을 임포트 하는 방식으로, 코드를 더 읽기 쉽게 만들고, import 시스템이 잘못 구성되었을때(패키지 내의 디렉토리가 sys.path에 포함되었을때) 더 나은 오류 메시지를 제공함. 라이브러리 코드의 의존성과 구조가 명확해져서 개발자가 코드를 더 쉽게 이해하고 사용할 수 있음.
상대 임포트 : 현재 모듈 위치에 상대적인 경로를 사용하여 모듈을 임포트 하는 방식. 복잡한 패키지 레이아웃을 가진 경우, 덜 번거롭고 코드를 간결하게 유지할 수 있음. 상대 임포트는 코드가 어떤 위치에 있는지 파악하기 어렵게 만들 수 있으므로, 명확한 프로젝트 구조에 주로 사용함.

# 절대 import - 가장 좋음
import mypkg.sibling 
from mypkg import sibling 
from mypkg.sibling import example 

# 명시적인 상대 import 
from . import sibling 
from .sibling import example

# 와일드카드(*)는 피하기
from mypkg import *

직접 클래스 임포트 : 클래스를 모듈에서 직접 임포트. 모듈의 네임스페이스를 통하지 않고 바로 사용할 수 있음. 특정 클래스만을 명시적으로 임포트하여 사용하므로 코드가 간결하고 읽기 쉬워짐.
모듈 임포트 : 로컬이름이 충돌을 일으킬 경우(같은 이름의 클래스나 변수가 존재하는 경우) 모듈을 전체적으로 임포트하는 것이 좋음. 모듈 이름과 함께 클래스 이름을 명시해야함.

# 직접 클래스 임포트
from myclass import MyClass
from foo.bar.yourclass import YourClass

# 모듈 임포트
import myclass
import foo.bar.yourclass

x = myclass.MyClass()
y = foo.bar.yourclass.YourClass()

Module Level Dunder Names
Dunder Method : 언더스코어 2개가 붙는 메소드. Double UNDERscore Method.
Dunder는 모듈 docstring 뒤에, from __future__imports를 제외한 모든 import문 앞에 놓여야함.

"""This is the example module.

This module does stuff.
"""

from __future__ import barry_as_FLUFL

__all__ = ['a', 'b', 'c']
__version__ = '0.1'
__author__ = 'Cardinal Biggles'

import os
import sys

3. String Quotes

파이썬에서는 문자열을 사용할때 작은따옴표든 큰 따옴표든 상관없지만 일관되게 사용해야함.
3개의 따옴표로 된 문장의 경우, 큰 따옴표를 사용함.

4. Whitespace in Expressions and Statements

Pet Peeves

# 소괄호/중괄호/대괄호 바로 안쪽은 공백 금지
#
# 👍🏻 좋은예:
spam(ham[1], {eggs: 2})
# 👎🏻 나쁜예:
spam( ham[ 1 ], { eggs: 2 } )


# 끝의 콤마와 괄호 사이는 공백 금지
#
# 👍🏻 좋은예:
foo = (0,)
# 👎🏻 나쁜예:
bar = (0, )


# 콤마, 세미콜론, 콜론 바로 앞은 공백 금지
#
# 👍🏻 좋은예:
if x == 4: print(x, y); x, y = y, x
# 👎🏻 나쁜예:
if x == 4 : print(x , y) ; x , y = y , x


# 슬라이싱에서 콜론은 이항연산자처럼 양쪽 둘다 동일한 공백. 확장슬라이싱에서는 두 콜론의 간격이 동일해야함. 
# 예외: 매개변수를 생략하면 공백도 생략.
#
# 👍🏻 좋은예:
ham[1:9], ham[1:9:3], ham[:9:3], ham[1::3], ham[1:9:]
ham[lower:upper], ham[lower:upper:], ham[lower::step]
ham[lower+offset : upper+offset]
ham[: upper_fn(x) : step_fn(x)], ham[:: step_fn(x)]
ham[lower + offset : upper + offset]
# 👎🏻 나쁜예:
ham[lower + offset:upper + offset]
ham[1: 9], ham[1 :9], ham[1:9 :3]
ham[lower : : step]
ham[ : upper]

# 함수를 호출할때 여는 괄호 바로 앞은 공백 금지
#
# 👍🏻 좋은예:
spam(1)
# 👎🏻 나쁜예:
spam (1)

# 인덱스와 슬라이싱을 여는 괄호 바로 앞은 공백 금지
#
# 👍🏻 좋은예:
dct['key'] = lst[index]
# 👎🏻 나쁜예:
dct ['key'] = lst [index]


# 변수 할당시 다른 변수와 줄을 맞추는 공백 금지
#
# 👍🏻 좋은예:
x = 1
y = 2
long_variable = 3
# 👎🏻 나쁜예:
x             = 1
y             = 2
long_variable = 3

Other Recommendations

# 맨 뒤에오는 공백은 금지.

# 이항연산자 앞뒤로 공백.
#
# 👍🏻 좋은예:
1 + 1 = 2
# 👎🏻 나쁜예:
1+1=2

# 우선순위가 다른 연산자를 사용하는 경우, 우선순위가 낮은 연산자 앞뒤로 공백. 한칸외에 공백을 넣지말고, 앞뒤로 동일하게 공백을 주어야함.
#
# 👍🏻 좋은예:
i = i + 1
submitted += 1
x = x*2 - 1
hypot2 = x*x + y*y
c = (a+b) * (a-b)
# 👎🏻 나쁜예:
i=i+1
submitted +=1
x = x * 2 - 1
hypot2 = x * x + y * y
c = (a + b) * (a - b)

# 함수의 어노테이션은 콜론과 동일한 규칙을 따르며, '->' 양쪽에 공백.
#
# 👍🏻 좋은예:
def munge(input: AnyStr): ...
def munge() -> PosInt: ...
# 👎🏻 나쁜예:
def munge(input:AnyStr): ...
def munge()->PosInt: ...

# 키워드인자를 사용할 경우, '='앞뒤에는 공백 금지.
#
# 👍🏻 좋은예:
def complex(real, imag=0.0):
    return magic(r=real, i=imag)
# 👎🏻 나쁜예:
def complex(real, imag = 0.0):
    return magic(r = real, i = imag)

# 기본값을 가지는 인자 어노테이션을 하비는 경우, '=' 앞뒤에 공백
#
# 👍🏻 좋은예:
def munge(sep: AnyStr = None): ...
def munge(input: AnyStr, sep: AnyStr = None, limit=1000): ...
# 👎🏻 나쁜예:
def munge(input: AnyStr=None): ...
def munge(input: AnyStr, limit = 1000): ...

# 같은 라인에 여러개의 statements 금지
#
# 👍🏻 좋은예:
if foo == 'blah':
    do_blah_thing()
do_one()
do_two()
do_three()
# 👎🏻 나쁜예:
if foo == 'blah': do_blah_thing()
do_one(); do_two(); do_three()

# 간단한 if/for/while이면 한줄에 적는 건 괜찮음. 조건이 많은 문장에서는 한줄에 적기 금지.
#
# 👎🏻 나쁜예:
if foo == 'blah': do_blah_thing()
for x in lst: total += x
while t < 10: t = delay()
# 👎🏻 더 나쁜예:
if foo == 'blah': do_blah_thing()
else: do_non_blah_thing()

try: something()
finally: cleanup()

do_one(); do_two(); do_three(long, argument,
                             list, like, this)

if foo == 'blah': one(); two(); three()

5. When to Use Trailing Commas

끝에 콤마를 붙이는 건 선택사항이며, 끝에 콤마를 붙인 후에는 명확성을 위해 괄호로 둘러싸자.

# 👍🏻 좋은예:
FILES = ('setup.cfg',)

# 👎🏻 나쁜예: 괄호가 없는데 뒤에 콤마를 붙인 경우.
FILES = 'setup.cfg',

끝에 콤마를 붙이는 것은 값 등이 추가될 예정이면 유지보수에 도움이 됨.
사용방법은 한 줄에 값 하나씩, 끝에 콤마를 추가하고 줄바꿈을 함.
더이상 값이 없으면 다음 줄에 괄호로 닫아줌.

# 👍🏻 좋은예:
FILES = [
    'setup.cfg',
    'tox.ini',
    # 여기에 추가,
    ]
initialize(FILES,
           error=True,
           )

# 👎🏻 나쁜예:
FILES = ['setup.cfg', 'tox.ini',]
initialize(FILES, error=True,)           
           

6. Comments

모순된 주석은 주석이 없는 것보다 나쁘다. 코드를 바꿀 때마다 주석도 업데이트 해주기!
주석은 완전한 문장으로 마침표로 끝내야하며, 여러 문장의 주석인 경우 주석사이에 한두칸의 공백을 두어야함.
특히, 내가 쓴 주석이 다른 사람이 보기에도 쉽게 이해할 수 있는지 확인해야함.

Block Comments
블록주석은 주석을 해당 코드와 동일한 레벨의 들여쓰기를 해야함.
주석은 #단일 공백(' ')으로 시작.
블록주석의 단락은 공백의 한 줄이 아닌 단일 # 을 포함한 줄로 구분함.

# 주석입니다
#
# 주석입니다

Inline Comments
코드와 동일한 줄에 있는 인라인주석은 자제해서 사용하기.
인라인주석을 사용해야한다면 코드와 적어도 2칸의 공백으로 구분되어야하고, 너무 명확한걸 나타내는 용으로는 사용하면 안됨. 어떤 목적의 코드인지 나타내는 용으로 사용하기.

# 👍🏻 좋은예:
x = x + 1     # 목적 : Compensate for border

# 👎🏻 나쁜예:
x = x + 1     # 증가

Documentation Strings
좋은 Documnetation Strings(docstrings)를 작성하는 방법은 PEP 257 참고.
docstrings은 퍼블릭 모듈, 함수, 클래스, 메소드 등이 수행하는 일을 설명하는데 사용되며, def 뒤에 와야함.

# 여러 줄의 docstrings는 줄바꿈 후에 """만 입력. 
"""Return a foobang
Optional plotz says to frobnicate the bizbaz first.
"""

# 한 줄의 docstrings면 같은 줄에 """로 끝내기.
"""Return an ex-parrot."""

7. Naming Conventions

Overriding Principle
퍼블릭 API에서는 구형방식보다는 사용법에 따라 명명해야함. 즉 API를 사용하는 개발자들이 해당이름을 보았을때, 그 기능이나 역할을 쉽게 이해할 수 있어야함.

Descriptive:Naming Styles
가장 잘 쓰이는 네이밍 스타일

  • b(single lowercase letter) : 임시변수나 특정한 작은 범위의 반복변수(i,j등)
  • B(single uppercase letter) : 잘 사용되지 않으나, 수학적 계산에서 큰 범위의 상수를 표현할 때
  • lowercase
  • lower_case_with_underscores/snake case : 가장 권장!
  • UPPERCASE : 주로 상수에 사용됨.
  • UPPER_CASE_WITH_UNDERSCORES : 주로 상수에 사용됨.
  • CapitalizedWords/CapWords/CamelCase/StudlyCaps : 클래스 이름에 사용됨
    * 약어를 사용할 경우 약어의 모든 문자는 대문자. HttpServerError보다는 HTTPServerError.
  • mixedCase : 첫글자가 소문자. 주로 private 메소드나 내부변수에 사용됨.
  • Capitalized_Words_With_Underscores : 사용 자제. 가독성 떨어짐.

접두어, 접미어 사용

  • 단일 밑줄 접두어(_) : 모듈 내에서 비공개적으로 사용될 이름. _private
  • 단일 밑줄 접미어(_) : 파이썬 키워드와의 이름 충돌을 피하기 위해 사용. class_
  • 더블 밑줄 접두어(__) : 클래스 속성을 맹글링하기 위해 사용되어 서브클래스에서 속성 이름 충돌을 방지함. __attr은 클래스 내에서 _<ClassName>__attr로 변환됨.
  • 더블 밑줄 접두어와 접미어(__) : 매직 매소드나 특수 속성에 사용됨. __init__ 등

Prescriptive:Naming Conventions

  • 특정 문자의 사용 피하기. 예를들어, l(소문자L), O(대문자 O), I(대문자I)는 1, 0과 구분히 어렵기 때문에 단일문자 변수 이름으로 사용하지 않기
  • ASCII 호환성 유지하기. PEP3131정책.
  • 모듈 이름은 간결하고 모두 소문자로 작성. 모듈이름에 언더스코어 사용은 가능하지만, 가독성향상시킬때만 권장됨.
  • 패키지 이름은 간결하고 모두 소문자로 작성. 다른 환경(URL, 경로명 등)에서도 일관성 유지를 위해 언더스코어 사용 지양
  • 클래스 이름은 각 단어의 첫글자는 대문자로 하고 나머지는 소문자로 작성(CapWords). snake_case를 적용하는 클래스도 있긴함.
  • 파이썬의 내장이름(builtin names)은 단일 단어로 구성되거나 두 단어가 붙어있는 형태(len, max, input 등). 단, 예외 이름과 내장 상수에는 CapWords가 적용됨. 예외의 경우 IndexError 등, 내장상수로는 True, False, None 등.
  • 타입변수(제네릭 타입을 정의할때 사용)는 CapWords가 적용됨. 공변성과 반공변성을 표시하는 경우, 접미사 _co, _contra 추가하여 명시함.
  • 파이썬에서 예외는 클래스로 정의되므로 CapWords가 적용됨. ValueError, TypeError등. 예외를 명시하기 위해 접미사 Error 붙이기.
  • 글로벌변수는 lower_case_with_underscores 방식을 사용함.
  • 함수나 변수에는 소문자와 언더스코어를 사용하여 단어를 구분함(lower_case_with_underscores).
  • 인스턴스 메소드의 첫번째 인자는 self, 클래스 메소드의 첫번째 인자는 cls, 키워드와 이름이 충돌하는 경우 접미사(_) 추가하기.
  • 메소드 이름은 lower_case_with_underscores
  • 상수는 UPPER_CASE_WITH_UNDERSCORES.

Public and Internal Interfaces
공개 인스턴스와 내부 인스턴스를 명확히 구분할 수 있어야함.
공개 인스턴스는 일반적으로 문서화 되어있음. __all__속성을 사용하여 공개 API에 포함된 이름을 명시적으로 선언해야함.
내부 인스턴스는 이름앞에 (_)를 붙여서 내부적으로만 사용되어야함을 나타냄.

8. Programming Recommendations

  • 파이썬 코드를 작성할때는 다양한 파이썬 구현체(CPython, PyPy, Jthon 등)가 효과적으로 작동할 수 있도록 고려해야함.
  • 문자열 결합을 위해 ''.join() 형태를 사용하는 것이 권장됨.
  • 파이썬에서 None과 같은 싱글턴(singleton) 값과의 비교는 is 또는 is not 연산자를 사용하여 수행해야함(등호 연산자(== 또는 !=)를 사용X)
  • if x와 if x is not None의 차이 : if x는 x가 참인지 평가. None이든 False, 빈컨테이너, 0, 0.0이여도 False로 평가함. 만약 None으로 초기화된 변수나 인자가 다른값으로 설정되었는지 확인하고 싶을때는 if x is not None을 사용해야함.
  • is not 사용 : not ... is 구문보다 훨씬 가독성, 명확성 면에서 is not이 나음.
  • Python에서 풍부한 비교 연산을 구현할 때는, 모든 여섯 가지 비교 연산자(__eq__, __ne__, __lt__, __le__, __gt__, __ge__)를 직접 구현하는 것이 좋음
  • 파이썬에서 함수를 정의할때 lambda보다 def문을 사용하는 것을 권장.
  • 예외처리할때 BaseException 대신 Exception에서 상속
  • 하나의 예외가 다른 예외에 의해 발생되었을경우(Exception Chaining) raise X from Y를 사용하여 원본 추적정보를 잃지 않고 하나의 예외(X)가 다른 예외(Y)에 의해 발생했음을 나타내어야함.
  • 예외를 처리할때는 가능한 구체적인 예외를 명시하기. except:절 대신에 구체적인 예외사용(범용적인 except:은 except BaseException:과 동일). 모든 예외를 잡고 싶다면 except Exception 사용하기.
  • 예외 계층 구조를 사용하기
  • try/except 절에서 try절을 반드시 필요한 최소한의 코드로 제한하는 것이 중요. 예외가 발생할 수 있는 부분만 try절에 넣고 이외의 코드는 별도의 블록으로 처리하기.
  • 특정 코드 섹션에 로컬한 리소스가 있는 경우, with 문 사용하기. with문을 사용하면 리소스를 사용하는 코드 블록을 나타내고 블록을 빠져나올때 리소스정리가 자동으로 처리됨.
# with 문 사용
with open('file.txt', 'r') as f:
    content = f.read()
    # 파일 사용
# 이 시점에서 파일은 자동으로 닫힘

# try/finally 문 사용
f = open('file.txt', 'r')
try:
    content = f.read()
    # 파일 사용
finally:
    f.close()
  • 컨텍스트 매니저가 하는일을 명확하기 표시. begin_transaction() 메서드를 통해 명시적으로 트랜잭션을 시작하고, 이후에는 해당 트랜잭션 내에서 수행할 작업을 처리
# 👍🏻 좋은예:
with conn.begin_transaction():
    do_stuff_in_transaction(conn)

# 👎🏻 나쁜예:
with conn:
    do_stuff_in_transaction(conn)
  • 함수내의 반환문은 일관성이 있어야함. 함수내의 모든 반환문이 표현식을 반환하거나 아무것도 반환하지 않아야함. 어떤 반환문이 표현식을 반환한다면, 값이 반환되지 않는 반환문은 return None으로 표현되어야함.
  • 문자열의 접미사, 접두사를 확인하기 위해 문자열 슬라이싱보다는 startswith()와 endswith()를 사용하는 것이 좋음.
  • 객체의 타입을 비교할 때는 직접 타입을 비교(type())하는 것보다 isinstance()를 사용하는 것이 좋음.
  • boolean을 True 또는 False와 == 연산자를 사용하여 비교하지 말기.
  • try...finally의 finally 블록 내에서 return, break, continue와 같은 흐름 제어 문을 사용하는 것은 권장되지 않음. finally 블록 밖으로 점프하기 때문에 finally 블록 내에서 전파되고 있는 활성 예외를 암시적으로 취소하기 때문.

Function Annotation
함수 어노테이션은 PEP484 구문을 따라야함. 함수 어노테이션을 다르게 사용하려는 코드에 대해서는 파일 상단에 # type : ignore 주석을 추가하여 타입 체커가 모든 어노테이션을 무시하도록 지시할 수 있음.

# type은 매개변수의 예상 타압. return_type은 함수 반환값의 타입.
def function_name(parameter: type, ...) -> return_type:
    ...

Variable Annotation

  • 모듈 수준의 변수, 클래스 및 인스턴스 변수, 로컬변수의 어노테이션에는 콜론 뒤에 하나의 공백이 있어야함.
  • 콜론 앞에는 공백이 없어야함
  • 할당문에 우변이 있는 경우 등호 양쪽에 정확히 하나의 공백이 있어야함.
# 👍🏻 좋은예:
code: int

class Point:
    coords: Tuple[int, int]
    label: str = '<unknown>'

# 👎🏻 나쁜예:
code:int  # 콜론 뒤에 공백이 없음
code : int  # 콜론 앞에 공백이 있음

class Test:
    result: int=0  # 등호 주변에 공백이 없음

0개의 댓글