Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python 개선 제안 한국어 번역

PEP 840 – 클래스 네임스페이스에서의 이름 결정

Author:
Jeremy Hylton <jeremy at python.org>, Guido van Rossum <guido at python.org>
Discussions-To:
Discourse thread
Status:
Draft
Type:
Standards Track
Created:
15-Jul-2026
Python-Version:
3.16
Post-History:
16-Jul-2026

Table of Contents

번역·라이선스 안내

이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain or CC0-1.0, whichever is more permissive 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판

초록

클래스에서 변수 이름을 결정하는 방식에는 오래된 비일관성이 있습니다. 이 비일관성을 해결하기 위한 몇 가지 대안을 논의합니다.

동기

클래스 네임스페이스에서의 이름 결정은 부분적인 동적 조회를 사용합니다. 이름은 클래스 본문이 실행되는 동안 그 이름에 대한 대입이 일어났는지에 따라 지역 이름이 될 수도 있고 전역 이름이 될 수도 있습니다. 이름이 대입 전에 사용되면 전역(및 내장) 네임스페이스에서 조회됩니다.

클래스가 함수 스코프 안에서 정의되면, 이름이 가장 가까운 둘러싼 스코프로 결정될 수 있습니다. 이름이 둘러싼 스코프의 지역 이름이지만 바인딩되지 않았다면 NameError가 발생합니다.

겉으로 드러나는 일관성 문제는 같은 클래스 블록 안에서 이름이 지역 이름이면서 동시에 전역 이름일 수는 있지만, 지역 이름이면서 동시에 자유 이름일 수는 없다는 점입니다. 달리 말하면, 클래스가 최상위 수준에서 정의되었는지 다른 블록 안에서 정의되었는지에 따라 클래스 안에서의 이름 결정이 다르게 동작합니다. 전역 변수가 존재하면, 그 변수가 클래스를 둘러싼 스코프에서 바인딩되어 있지 않은 한 자유 변수를 결정하는 데 전역 변수가 사용될 수 있습니다.

다음은 클래스에서 자유 변수를 결정하는 예입니다:

>>> x = 0
>>> def f(x):
...     class A:
...         a = x
...     return A
...
>>> A = f(1)
>>> A.a  # the value of the parameter x, not the global x
1

변수 x는 함수의 매개변수 x로 결정됩니다. 전역 변수는 무시됩니다. 이 동작은 PEP 227과 PEP 3104에 정의된 표준 이름 결정 방식입니다.

x가 지역 변수로 사용되면, 최상위 수준과 다른 블록 안에서의 동작이 달라집니다. 같은 코드가 x를 지역 변수로도 사용하면, x에 대한 첫 번째 참조가 다르게 결정됩니다.

>>> x = 0
>>> def f(x):
...     class A:
...         a = x
...         x = 42
...     return A
...
>>> A = f(1)
>>> A.a  # the value of the global x, not the parameter x
0

x에 대한 첫 번째 참조는 더 이상 f에서 정의된 지역 변수 x에 바인딩되지 않고, 대신 전역 변수를 사용합니다.

조회할 네임스페이스의 집합은 어휘적으로 결정되지만, 특정 참조가 전역 네임스페이스를 사용하여 결정될지는 정적으로 판단할 수 없습니다.

>>> x = 0
>>> def f(var):
...     class A:
...         x = 10
...         if var in locals():
...             del locals()[var]
...         a = x
...     return A
...
>>> A1 = f("x")
>>> A2 = f("y")
>>> A1.a, A2.a
(0, 10)

배경

Python 2.0 정의는 각 이름에 대해 확인할 네임스페이스를 정확히 세 개로 규정합니다 – 지역 네임스페이스, 전역 네임스페이스, 내장 네임스페이스입니다. Python 2.1부터는 어휘적 스코핑이 사용되어 자유 변수가 둘러싼 스코프의 바인딩으로 결정될 수 있게 되었습니다. 클래스 네임스페이스는 특수한 경우여서, 자유 변수가 둘러싼 스코프에서 결정되지 않았습니다. 클래스 네임스페이스는 지역 네임스페이스와 전역 네임스페이스를 명시적으로 확인하는 특수한 LOAD_NAME / STORE_NAME 옵코드를 사용했습니다.

Python 3.4에서는 클래스 안의 자유 변수가 둘러싼 스코프에서 결정되었지만, 대입 전에 사용된 지역 변수는 여전히 전역 스코프에서 결정되었습니다. 이때 언어 명세가 갱신되지 않았기 때문에, 명세는 여전히 3.4 이전의 동작을 규정하고 있습니다:

클래스 정의는 이름을 사용하고 정의할 수 있는 실행 가능한 문장입니다. 이러한 참조는 이름 결정의 일반 규칙을 따르지만, 바인딩되지 않은 지역 변수는 전역 네임스페이스에서 조회된다는 예외가 있습니다.

클래스 네임스페이스와 최상위 모듈 네임스페이스는 모두 초기의 지역 / 전역 / 내장 스코프 규칙을 반영하는 LOAD_NAME / STORE_NAME 옵코드를 사용합니다. 클래스 네임스페이스는 클래스 네임스페이스가 클래스 객체의 속성이 된다는 점에서도 특별합니다. 이러한 차이 때문에 PEP 227을 작성할 때 클래스에 적용되는 서로 다른 스코프 규칙은 고려되지 않았습니다.

2002년에 버그가 하나 보고되었습니다. PEP 작성자는 “그 결함을 악용하는 코드를 작성하지 마십시오.”라는 코멘트와 함께 버그를 닫았습니다. https://github.com/python/cpython/issues/36300 2010년에 또 다른 버그가 보고되었고, 이번에는 같은 작성자가 변경을 제안하게 되었습니다. https://github.com/python/cpython/issues/53472 네임스페이스의 동작이 일관되지 않으면 똑같은 버그에도 일관되지 않은 대응이 나올 수 있는 듯합니다.

제안

선택할 수 있는 대안이 여러 가지 있습니다. 몇 가지 단순한 대안은 잘못된 것으로 보입니다. 3.4 이전의 동작으로 되돌릴 수도 있지만, 클래스 스코프에서 자유 변수가 동작하지 않았다는 점은 놀라운 일이었습니다. 현재 동작을 유지할 수도 있지만, 일관성이 없어 보입니다.

한 가지 방법은 클래스 네임스페이스가 함수 네임스페이스와 더 비슷하게 동작하도록 만드는 것입니다. 지역 변수가 바인딩되지 않은 시점에 사용되면 NameError가 발생합니다. 이 규칙은 단순하고 일관성이 있습니다. 이 방법의 주된 단점은 기존 코드가 동작하지 않게 된다는 것입니다. 이 기능에 의존하는 코드는 지역 참조와 전역 참조 중 어느 쪽을 의도했는지 읽는 사람이 알아내야 하므로 이해하기 어렵습니다. 하지만 이해하기 어렵다는 것이 정의되지 않았다거나 잘못되었다는 것과 같은 뜻은 아닙니다

또 다른 방법은 이름이 바인딩되지 않았을 때 전역 네임스페이스를 사용하도록 자유 변수 해석 동작을 변경하는 것입니다. 둘러싼 스코프에서 변수가 바인딩되지 않아 현재 코드라면 NameError가 발생할 경우, 그 변수를 전역 네임스페이스에서 해석하게 됩니다.

두 번째 방법을 미묘하게 변형한 세 번째 방법도 있습니다. 지역 변수가 바인딩되지 않았고 그 변수가 둘러싼 스코프에 바인딩을 가지고 있다면, 전역 네임스페이스 대신 해당 네임스페이스를 사용합니다.

>>> x = 0
>>> def f():
...     x = 1
...     class A:
...         x = 2
...         del x
...         a = x # Should this use f's local or global?
...     return A
...
>>> A = f()
>>> A.a
?

지역 변수가 바인딩되지 않았는데 어차피 다른 네임스페이스에서 해석할 수 있다면, 왜 전역 네임스페이스만 사용해야 합니까? 표준 이름 해석 규칙 전체를 사용하지 않을 이유가 있습니까?

이 방법이 가장 일관성 있어 보이지만, 구현이 더 복잡해집니다. 특정 시점에 변수가 바인딩되어 있는지는 정적으로 판단할 수 없으므로, 둘러싼 스코프의 지역 변수를 가리는 클래스의 지역 변수마다 셀을 할당해야 합니다. 지역 변수를 동적으로 조작하는 일은 드물기 때문에, 이를 위해 추가로 필요한 클로저는 거의 항상 사용되지 않을 것으로 예상됩니다. 그렇기는 하지만 이는 다소 드문 경우일 것입니다. 곧, 둘러싼 스코프의 지역 변수를 가리는 지역 변수를 가진 중첩 클래스 정의입니다.