Python 의 키워드 및 내장 식별자

PythonBeginner
지금 연습하기

소개

본 실습에서는 Python 의 예약어 (reserved words) 와 내장 이름 (pre-defined names) 의 기본 개념을 탐구합니다. 먼저, 변수나 함수 이름으로 사용할 수 없는 특별한 의미를 지닌 단어인 Python 키워드를 식별하는 방법을 배웁니다. 이를 위해 내장 모듈인 keyword를 사용하여 키워드 목록을 확인할 것입니다.

다음으로, 코드에서 항상 사용할 수 있는 함수 및 상수와 같은 Python 의 내장 식별자 (built-in identifiers) 를 알아봅니다. 마지막으로, 오류를 방지하고 코드를 깔끔하고 기능적으로 유지하기 위해 자신만의 이름에 키워드와 내장 식별자를 사용하는 것을 피해야 하는 이유를 살펴봅니다.

Python 키워드 식별하기

이 단계에서는 Python 키워드에 대해 알아봅니다. 예약어 (reserved words) 라고도 불리는 키워드는 언어 구문의 기본 구성 요소입니다. 이들은 특별한 의미를 가지며 변수, 함수 또는 기타 식별자의 이름으로 사용할 수 없습니다.

Python 은 현재 모든 키워드를 쉽게 확인할 수 있도록 keyword라는 내장 모듈을 제공합니다. 이를 표시하는 스크립트를 작성해 보겠습니다.

필요한 파일인 list_keywords.py는 이미 생성되어 있습니다. WebIDE 왼쪽의 파일 탐색기에서 해당 파일을 찾아 클릭하여 엽니다.

이제 list_keywords.py 파일에 다음 코드를 추가합니다.

import keyword

## kwlist 속성에는 모든 키워드 목록이 포함되어 있습니다.
print(keyword.kwlist)

파일을 저장한 후, WebIDE 에서 통합 터미널 (integrated terminal) 을 엽니다. 상단 메뉴에서 Terminal -> New Terminal을 클릭하여 열 수 있습니다.

터미널에서 다음 명령을 실행하여 스크립트를 실행합니다.

python ~/project/list_keywords.py

출력 결과는 모든 Python 키워드 목록이 될 것입니다.

['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']

이 단어들이 예약어라는 점을 기억하는 것이 중요합니다. Python 은 대소문자를 구분하므로, if는 키워드이지만 IF는 키워드가 아닙니다. 하지만 코드의 명확성을 유지하기 위해 키워드의 변형을 이름으로 사용하는 것은 피하는 것이 가장 좋습니다.

Python 내장 식별자 탐색하기

이제 Python 의 내장 식별자 (built-in identifiers) 를 탐색해 보겠습니다. 이들은 print()와 같은 일반적인 함수, intstr과 같은 데이터 타입, 예외 (exceptions) 를 포함하여 Python 이 사용자에게 미리 정의해 둔 이름들입니다. 이들은 import 문 없이도 모든 Python 스크립트에서 항상 사용할 수 있습니다.

__builtins__라는 특별한 객체에 대해 dir() 함수를 사용하여 모든 내장 식별자의 목록을 볼 수 있습니다.

파일 탐색기에서 list_builtins.py 파일을 엽니다. 다음 코드를 파일에 추가합니다.

## dir() 는 __builtins__ 범위 내의 이름 목록을 반환합니다.
print(dir(__builtins__))

파일을 저장하고 터미널에서 스크립트를 실행합니다.

python ~/project/list_builtins.py

콘솔에 긴 이름 목록이 출력되는 것을 볼 수 있습니다. 아래는 출력의 일부를 발췌한 것입니다.

['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EncodingWarning', 'EnvironmentError', 'Exception', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'ModuleNotFoundError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'RecursionError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '__build_class__', '__debug__', '__doc__', '__import__', '__loader__', '__name__', '__package__', '__spec__', 'abs', 'aiter', 'all', 'anext', 'any', 'ascii', 'bin', 'bool', 'breakpoint', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']

이 목록에서 len, input, list, dict와 같이 유용한 많은 이름을 발견할 수 있을 것입니다. 다음 단계에서는 이러한 이름을 자신의 변수에 사용해서는 안 되는 이유를 알게 될 것입니다.

식별자로 키워드 사용 피하기

이 단계에서는 Python 키워드를 변수 이름으로 사용하려고 할 때 어떤 일이 발생하는지 확인할 것입니다. 키워드는 언어 구조를 위해 예약되어 있으므로, 키워드에 값을 할당하려고 시도하면 프로그램이 실행되기도 전에 실패하게 됩니다.

키워드 with를 변수 이름으로 사용하려고 시도하여 이를 시연해 보겠습니다.

WebIDE 편집기에서 keyword_error.py 파일을 엽니다. 의도적으로 잘못된 다음 코드를 추가합니다.

## 'with'는 키워드이므로 오류가 발생합니다.
with = 5
print(with)

파일을 저장하고 터미널에서 실행해 봅니다.

python ~/project/keyword_error.py

Python 은 즉시 중단되고 SyntaxError를 보고합니다.

  File "/home/labex/project/keyword_error.py", line 2
    with = 5
    ^^^^
SyntaxError: invalid syntax

SyntaxError: invalid syntax라는 오류 메시지는 코드가 잘못 구성되었음을 명확하게 나타냅니다. 이는 Python 인터프리터가 with를 값을 저장할 수 있는 이름이 아니라 with 문을 시작해야 하는 키워드로 인식하기 때문에 발생합니다. 이 규칙은 첫 번째 단계에서 나열한 모든 키워드에 적용됩니다.

내장 식별자 덮어쓰기 방지

키워드와 달리 Python 은 내장 식별자를 재할당하는 것을 막지 않습니다. 하지만 그렇게 하는 것은 버그의 흔한 원인이 되므로 피해야 합니다. 내장 이름에 새 값을 할당하면 원래의 기능이 "가려져서" 예상치 못한 오류가 발생할 수 있습니다.

내장 print 함수를 덮어쓸 때 어떤 일이 발생하는지 살펴보겠습니다.

WebIDE 편집기에서 builtin_override.py 파일을 엽니다. 다음 코드를 추가합니다.

## 내장 print 함수를 정수 (integer) 로 덮어씁니다.
print = 5

## 이제 print() 를 함수처럼 사용해 봅니다.
print("hello")

파일을 저장하고 터미널에서 실행합니다.

python ~/project/builtin_override.py

이번에는 스크립트가 실행을 시작하지만 TypeError와 함께 실패합니다.

Traceback (most recent call last):
  File "/home/labex/project/builtin_override.py", line 5, in <module>
    print("hello")
TypeError: 'int' object is not callable

오류 TypeError: 'int' object is not callable가 발생하는 이유는 이름 print가 더 이상 내장 인쇄 함수를 참조하지 않기 때문입니다. 대신, 정수 5를 참조합니다. 정수를 함수처럼 "호출"할 수 없으므로 (괄호 사용), 프로그램이 충돌합니다.

이는 내장 객체를 덮어쓰는 것의 위험성을 보여줍니다. 이는 명확하지 않은 방식으로 코드를 손상시키고 디버깅을 어렵게 만들 수 있습니다. 이러한 충돌을 피하려면 변수와 함수에 항상 고유하고 설명적인 이름을 선택해야 합니다.

요약

본 실습에서는 Python 의 두 가지 중요한 이름 범주인 키워드 (keywords) 와 내장 식별자 (built-in identifiers) 에 대해 배웠습니다. keyword 모듈을 사용하여 Python 의 모든 예약된 키워드를 나열해 보았고, 이를 변수 이름으로 사용하려고 시도할 때 SyntaxError가 발생하는 것을 확인했습니다.

또한 내장 식별자 목록을 탐색하고, 이를 덮어쓸 때 발생하는 문제점들 (이는 TypeError 및 기타 런타임 문제로 이어질 수 있음) 을 시연해 보았습니다. 핵심 교훈은 코드의 안정성, 가독성 및 충돌 방지를 위해 변수와 함수에 항상 고유한 이름을 선택하고, 키워드와 내장 이름을 모두 피해야 한다는 것입니다.