범위 지정 규칙에 대한 간단한 설명?


472

파이썬 범위 규칙은 정확히 무엇입니까 ?

코드가있는 경우 :

code1
class Foo:
   code2
   def spam.....
      code3
      for code4..:
       code5
       x()

어디서 x찾을 수 있습니까? 가능한 목록은 다음과 같습니다.

  1. 둘러싸는 소스 파일에서
  2. 클래스 네임 스페이스에서
  3. 함수 정의에서
  4. for 루프 인덱스 변수에서
  5. for 루프 내부

또한 함수 spam가 다른 곳으로 전달 될 때 실행 중에 컨텍스트 가 있습니다. 람다 함수 가 약간 다르게 전달 될 수 있습니까?

어딘가에 간단한 참조 또는 알고리즘이 있어야합니다. 중간 파이썬 프로그래머에게는 혼란스러운 세상입니다.


2
범위 지정 규칙은 파이썬 문서 docs.python.org/3/reference/… 에서 상당히 간결하지만 완벽하게 설명되어 있습니다.
jefe2000

답변:


420

실제로, Python python 3의 Python Scope 해상도에 대한 간결한 규칙 . 에드 . (이 규칙은 속성이 아닌 변수 이름에만 적용됩니다. 마침표없이 참조하면이 규칙이 적용됩니다.)

LEGB 규칙

  • L ocal — 함수 ( def또는 lambda) 내에서 어떤 식 으로든 할당 되고 해당 함수에서 전역으로 선언되지 않은 이름

  • E 임의의 모든 정적 둘러싸 함수 (의 로컬 영역에 할당 된 이름 - nclosing 기능 def또는 lambda외측에서 내측으로)

  • G lobal (모듈) — 모듈 파일의 최상위에 할당되거나 파일 내에서 global명령문 을 실행하여 지정된 이름def

  • B의 : - (파이썬) 유형을 말한다 된 이름은 내장 된 이름의 모듈에 미리 할당 open, range, SyntaxError, 등

따라서

code1
class Foo:
    code2
    def spam():
        code3
        for code4:
            code5
            x()

for루프는 자신의 네임 스페이스가 없습니다. LEGB 순서에서 범위는

  • L : 로컬에서 def spam(에서 code3, code4그리고 code5)
  • E : 모든 포함 함수 (전체 예제가 다른 함수에있는 경우 def)
  • G : x모듈에서 전역으로 선언 된 것이 code1있습니까 (in )?
  • B : x파이썬 내장 .

x에서 찾을 수 없을 것입니다 code2(예상 할 수도 있지만 Antti의 답변 또는 here 참조 ).


45
전역 액세스에 대한 경고로 명시 적 선언없이 전역 변수를 읽을 수 있지만 global (var_name)을 선언하지 않고 변수를 작성하면 대신 새 로컬 인스턴스가 작성됩니다.
Peter Gibson

12
실제로 @Peter global(var_name)는 구문 상 올바르지 않습니다. 올바른 구문은 global var_name괄호 가 없습니다. 당신은 유효한 포인트가 있습니다.
martineau

그렇다면 foo의 "y"변수가 아래 "bar"에 표시되지 않는 이유는 무엇입니까? >>> def foo(x): ... y = x ... def bar(z): ... y = z ... bar(5) ... print x,y ... >>> foo(3) 3 3
Jonathan Mayer

3
@Jonathan : 각각 y에 쓰여지고 global y선언 이 없으므로 @Peter의 의견을 참조하십시오.
martineau

@LakshmanPrasad "E"에 빠지지만 언급 할 가치가있는 한 가지 특별한 동작이 있습니다. 이는 클래스 변수이므로 객체 중 "전역"입니다. 여기에 할당하면 됩니다 당신이 무슨 일을하는지 모르는 경우 디버그 문제에 예상치 못한 하드로 이어집니다.
Ctrl-C

157

본질적으로 파이썬에서 새로운 범위를 소개하는 유일한 것은 함수 정의입니다. 클래스는 본문에 직접 정의 된 항목이 클래스의 네임 스페이스에 배치되지만 포함 된 메서드 (또는 중첩 클래스)에서 직접 액세스 할 수 없다는 점에서 약간 특별한 경우입니다.

귀하의 예에는 x가 검색되는 범위가 3 개뿐입니다.

  • 스팸 범위-code3 및 code5에 정의 된 모든 항목 (루프 변수 code4는 물론)

  • 전역 범위-code1에 정의 된 모든 내용과 Foo (및 그 이후의 변경 사항 포함)

  • 내장 네임 스페이스 약간의 특별한 경우-len () 및 str ()과 같은 다양한 Python 내장 함수 및 유형이 포함되어 있습니다. 일반적으로 이것은 사용자 코드로 수정해서는 안되므로 표준 기능 만 포함하면됩니다.

더 많은 범위는 그림에 중첩 함수 (또는 람다)를 도입 할 때만 나타납니다. 그러나 이것은 예상대로 거의 작동합니다. 중첩 된 함수는 로컬 범위의 모든 항목과 둘러싸는 함수의 범위에있는 모든 항목에 액세스 할 수 있습니다. 예.

def foo():
    x=4
    def bar():
        print x  # Accesses x from foo's scope
    bar()  # Prints 4
    x=5
    bar()  # Prints 5

제한 사항 :

로컬 함수 변수 이외의 범위에있는 변수는 액세스 할 수 있지만 추가 구문 없이는 새 매개 변수로 리바운드 할 수 없습니다. 대신 할당은 상위 범위의 변수에 영향을주는 대신 새 로컬 변수를 만듭니다 . 예를 들면 다음과 같습니다.

global_var1 = []
global_var2 = 1

def func():
    # This is OK: It's just accessing, not rebinding
    global_var1.append(4) 

    # This won't affect global_var2. Instead it creates a new variable
    global_var2 = 2 

    local1 = 4
    def embedded_func():
        # Again, this doen't affect func's local1 variable.  It creates a 
        # new local variable also called local1 instead.
        local1 = 5
        print local1

    embedded_func() # Prints 5
    print local1    # Prints 4

함수 범위 내에서 전역 변수의 바인딩을 실제로 수정하려면 global 키워드를 사용하여 변수가 전역임을 지정해야합니다. 예 :

global_var = 4
def change_global():
    global global_var
    global_var = global_var + 1

현재 함수 범위 를 묶는 변수에 대해 동일한 작업을 수행 할 수있는 방법은 없지만 Python 3에서는 nonlocal전역 키워드 와 유사한 방식으로 동작하지만 중첩 된 함수 범위에 대해 " " 라는 새로운 키워드를 도입했습니다 .


111

Python3 시간에 대한 완전한 대답은 없었으므로 여기서 대답했습니다. 여기에 설명 된 대부분의 내용은 4.2.2 Python 3 문서 이름 확인에 자세히 설명되어 있습니다.

다른 답변에서 제공하는 것처럼 로컬, 인클로저, 글로벌 및 내장에 대한 4 가지 기본 범위 인 LEGB가 있습니다. 이외에도 클래스 범위 내에 정의 된 메소드의 엔 클로징 범위를 포함하지 않는 특수 범위 인 클래스 본문이 있습니다 . 클래스 본문 내에서 할당하면 변수가 클래스 본문에 바인딩됩니다.

특히 및 이외의 블록 문 은 변수 범위를 만들지 않습니다 . 파이썬 2에서는리스트 이해가 변수 범위를 생성하지 않지만, 파이썬 3에서는리스트 이해 내의 루프 변수가 새로운 범위로 생성됩니다.defclass

학급의 특성을 보여주기 위해

x = 0
class X(object):
    y = x
    x = x + 1 # x is now a variable
    z = x

    def method(self):
        print(self.x) # -> 1
        print(x)      # -> 0, the global x
        print(y)      # -> NameError: global name 'y' is not defined

inst = X()
print(inst.x, inst.y, inst.z, x) # -> (1, 0, 1, 0)

따라서 함수 본문과 달리 변수를 클래스 본문에서 동일한 이름으로 다시 할당하여 동일한 이름의 클래스 변수를 얻을 수 있습니다. 이 이름에 대한 추가 조회는 대신 클래스 변수로 해석됩니다.


파이썬을 처음 접하는 많은 사람들에게 큰 놀라움 중 하나는 for루프가 변수 범위를 만들지 않는다는 것입니다. Python 2에서 목록 이해는 범위를 만들지 않습니다 (제너레이터와 dict 이해력이있는 동안!) 대신 함수 또는 전역 범위에서 값을 유출합니다.

>>> [ i for i in range(5) ]
>>> i
4

이해는 파이썬 2에서 람다 식 내에서 수정 가능한 변수를 만드는 교활한 (또는 끔찍한 경우) 방법으로 사용될 def수 있습니다. 파이썬에서 명령문으로 할당한다는 것은 람다에서 변수 할당이 허용되지 않지만 목록 이해는 표현식이라는 것을 의미합니다.

이 동작은 Python 3에서 수정되었습니다. 이해 표현식이나 생성기 누출 변수가 없습니다.


전역은 실제로 모듈 범위를 의미합니다. 주요 파이썬 모듈은 __main__; 가져온 모든 모듈은 sys.modules변수를 통해 액세스 할 수 있습니다 . 에 액세스 __main__하려면 sys.modules['__main__'], 또는 import __main__; 속성을 액세스하고 할당하는 것은 완벽하게 허용됩니다. 메인 모듈의 전역 범위에 변수로 표시됩니다.


이름이 현재 범위 (클래스 범위 제외)에 할당 된 경우 해당 범위에 속하는 것으로 간주되고, 그렇지 않으면 변수에 할당되는 모든 범위에 속하는 것으로 간주됩니다 (할당되지 않을 수 있음) 아직 또는 전혀) 또는 마지막으로 글로벌 범위. 변수가 로컬로 간주되지만 아직 설정되지 않았거나 삭제 된 경우 변수 값을 읽으면의 UnboundLocalError하위 클래스 인가 NameError됩니다.

x = 5
def foobar():
    print(x)  # causes UnboundLocalError!
    x += 1    # because assignment here makes x a local variable within the function

# call the function
foobar()

범위는 global 키워드를 사용하여 전역 (모듈 범위) 변수를 명시 적으로 수정한다고 선언 할 수 있습니다.

x = 5
def foobar():
    global x
    print(x)
    x += 1

foobar() # -> 5
print(x) # -> 6

둘러싸는 범위에서 음영 처리 된 경우에도 가능합니다.

x = 5
y = 13
def make_closure():
    x = 42
    y = 911
    def func():
        global x # sees the global value
        print(x, y)
        x += 1

    return func

func = make_closure()
func()      # -> 5 911
print(x, y) # -> 6 13

파이썬 2에서는 둘러싸는 범위에서 값을 수정하는 쉬운 방법이 없습니다. 일반적으로 이것은 길이가 1 인 목록과 같이 변경 가능한 값을 가짐으로써 시뮬레이션됩니다.

def make_closure():
    value = [0]
    def get_next_value():
        value[0] += 1
        return value[0]

    return get_next_value

get_next = make_closure()
print(get_next()) # -> 1
print(get_next()) # -> 2

그러나 파이썬 3에서는 nonlocal구조가 시작됩니다.

def make_closure():
    value = 0
    def get_next_value():
        nonlocal value
        value += 1
        return value
    return get_next_value

get_next = make_closure() # identical behavior to the previous example.

nonlocal설명서를 말한다

글로벌 명령문에 나열된 것과 달리 로컬이 아닌 명령문에 나열된 이름은 둘러싸는 범위의 기존 바인딩을 참조해야합니다 (새 바인딩을 작성해야하는 범위를 명확하게 판별 할 수 없음).

즉, nonlocal항상 이름이 바인딩 된 가장 바깥 쪽의 비전 역 범위를 가리 킵니다 (예 : for대상 변수, with절 또는 함수 매개 변수 로 사용됨 ).


현재 범위 또는 로컬 범위에 로컬로 간주되지 않는 변수는 전역 변수입니다. 전역 이름은 모듈 전역 사전에서 조회됩니다. 찾지 못하면 전역이 내장 모듈에서 조회됩니다. 모듈 이름이 python 2에서 python 3으로 변경되었습니다. 파이썬 2에서는 였고 __builtin__파이썬 3에서는 이제라고 builtins합니다. 내장 모듈의 속성에 할당하면, 모듈이 동일한 이름을 가진 고유 한 전역 변수로 음영 처리되지 않는 한 그 모듈은 읽을 수있는 전역 변수로 모든 모듈에 표시됩니다.


내장 모듈을 읽는 것도 유용 할 수 있습니다. 파일의 일부 부분에서 python 3 스타일 인쇄 기능을 원하지만 파일의 다른 부분에서는 여전히 print명령문을 사용한다고 가정하십시오 . Python 2.6-2.7에서는 다음을 사용하여 Python 3 print기능 을 사용할 수 있습니다 .

import __builtin__

print3 = __builtin__.__dict__['print']

from __future__ import print_function실제로 가져 오지 않습니다 print파이썬 2의 기능 어디서나 - 대신 단지에 대한 구문 분석 규칙을 비활성화 print처리, 현재 모듈에서 문 print다른 변수 식별자처럼, 따라서 수 있도록 print기능이 내장 매크로에서 조회 할.


23

Python 2.x의 범위 지정 규칙은 이미 다른 답변에 설명되어 있습니다. 내가 추가 할 유일한 것은 Python 3.0에는 로컬이 아닌 범위 ( 'nonlocal'키워드로 표시됨)의 개념이 있다는 것입니다. 이를 통해 외부 스코프에 직접 액세스 할 수 있으며 어휘 클로저 (가변 객체를 포함하는 추악한 해킹없이)를 포함한 깔끔한 트릭을 수행 할 수 있습니다.

편집 : 여기에 대한 자세한 정보 가있는 PEP 가 있습니다.


23

범위의 약간 더 완전한 예 :

from __future__ import print_function  # for python 2 support

x = 100
print("1. Global x:", x)
class Test(object):
    y = x
    print("2. Enclosed y:", y)
    x = x + 1
    print("3. Enclosed x:", x)

    def method(self):
        print("4. Enclosed self.x", self.x)
        print("5. Global x", x)
        try:
            print(y)
        except NameError as e:
            print("6.", e)

    def method_local_ref(self):
        try:
            print(x)
        except UnboundLocalError as e:
            print("7.", e)
        x = 200 # causing 7 because has same name
        print("8. Local x", x)

inst = Test()
inst.method()
inst.method_local_ref()

산출:

1. Global x: 100
2. Enclosed y: 100
3. Enclosed x: 101
4. Enclosed self.x 101
5. Global x 100
6. global name 'y' is not defined
7. local variable 'x' referenced before assignment
8. Local x 200

6
이것은 좋은 대답입니다. 그러나, 나는 사이의 차이라고 생각 method하고 method_local_ref강조해야한다. method전역 변수에 액세스하여 에서처럼 인쇄 할 수 있습니다 5. Global x. 그러나 method_local_ref나중에 동일한 이름의 로컬 변수를 정의하기 때문에 불가능합니다. 당신은 x = 200라인 을 제거하여 이것을 테스트 하고 차이점을 볼 수 있습니다
kiril

@ brianray : z는 어떻습니까?
Malik A. Rumi

@kiril 나는 그것에 대해 메모를 추가
브라이언 레이

MalikA.Rumi 내가 Z를 제거 @ 그것은 재미 아니었다으로
brianray

놀랍게도 이것은 파이썬 범위에 대한 유일한 명확한 설명이며 모든 SO에서 찾을 수 있습니다. 아주 기본적인 예를 사용하면됩니다. 감사!
not2qubit

13

파이썬은 일반적으로 세 가지 네임 스페이스로 변수를 해결합니다.

실행 중 언제든지 네임 스페이스에 직접 액세스 할 수있는 중첩 된 범위가 세 개 이상 있습니다. 가장 먼저 검색되는 가장 안쪽 범위에는 로컬 이름이 포함됩니다. 가장 가까운 엔 클로징 범위에서 시작하여 검색되는 모든 엔 클로징 함수의 네임 스페이스 다음에 검색되는 중간 범위에는 현재 모듈의 전역 이름이 포함됩니다. 가장 바깥 쪽 범위 (마지막으로 검색)는 내장 이름이 포함 된 네임 스페이스입니다.

이 두 가지 기능은 다음과 같습니다 globalslocals내용 당신에게 이러한 네임 스페이스의 두 가지를 표시한다.

네임 스페이스는 패키지, 모듈, 클래스, 객체 구성 및 기능으로 생성됩니다. 다른 이름 공간은 없습니다.

이 경우 이름 지정된 함수에 대한 호출 x은 로컬 네임 스페이스 또는 글로벌 네임 스페이스에서 해결되어야합니다.

이 경우 로컬은 메소드 함수의 본문입니다 Foo.spam.

글로벌은 글로벌입니다.

규칙은 메소드 함수 (및 내포 된 함수 정의)로 작성된 내포 된 로컬 공간을 검색 한 후 글로벌을 검색하는 것입니다. 그게 다야.

다른 범위는 없습니다. for문 (와 같은 다른 복합 명령문 if과는 try) 새로운 중첩 된 범위를 작성하지 않습니다. 정의 (패키지, 모듈, 함수, 클래스 및 객체 인스턴스)

클래스 정의 내에서 이름은 클래스 네임 스페이스의 일부입니다. code2예를 들어, 클래스 이름으로 규정되어야합니다. 일반적으로 Foo.code2. 그러나 self.code2파이썬 객체는 포함하는 클래스를 폴백으로 간주하기 때문에 작동합니다.

객체 (클래스의 인스턴스)에는 인스턴스 변수가 있습니다. 이러한 이름은 객체의 네임 스페이스에 있습니다. 그것들은 객체에 의해 자격이 있어야합니다. ( variable.instance)

수업 방법 내에서 지역과 세계가 있습니다. self.variable인스턴스를 네임 스페이스로 선택 한다고 말합니다 . 이것이 self모든 클래스 멤버 함수에 대한 인수이므로 로컬 네임 스페이스의 일부가됩니다.

Python 범위 규칙 , Python 범위 , 변수 범위를 참조하십시오 .


5
오래되었습니다. 2.1 (7 년 전) 이후에는 중첩 함수가 새로운 범위를 도입하므로 두 개 이상의 범위가 있으므로 함수 내의 함수는 로컬 범위, 포함 함수 범위 및 전역 범위 (내장)에 액세스 할 수 있습니다.
브라이언

죄송합니다. 더 이상 해당되지 않습니다. Python has two namespaces available. Global and local-to-something.
Rizwan Kassim에

9

x는 어디에 있습니까?

정의하지 않은 x를 찾을 수 없습니다. :-) code1 (글로벌) 또는 code3 (로컬)에서 찾을 수 있습니다.

code2 (클래스 멤버)는 같은 클래스의 메서드 내부에서 코딩 할 수 없습니다. 일반적으로 self를 사용하여 액세스합니다. code4 / code5 (루프)는 code3과 동일한 범위에 있으므로 x를 쓰면 새 x를 만들지 않고 code3에 정의 된 x 인스턴스를 변경하게됩니다.

파이썬은 정적으로 범위가 정해져 있으므로, '스팸'을 다른 함수에 전달하면 스팸은 모듈의 코드 (코드 1에 정의 됨) 및 다른 포함 범위 (아래 참조)에 계속 액세스 할 수 있습니다. code2 멤버는 다시 self를 통해 액세스합니다.

람다는 데프와 다르지 않습니다. 함수 안에 람다를 사용하는 경우 중첩 함수를 정의하는 것과 같습니다. Python 2.2부터는 중첩 범위를 사용할 수 있습니다. 이 경우 모든 수준의 함수 중첩에서 x를 바인딩 할 수 있으며 Python은 가장 안쪽 인스턴스를 선택합니다.

x= 0
def fun1():
    x= 1
    def fun2():
        x= 2
        def fun3():
            return x
        return fun3()
    return fun2()
print fun1(), x

2 0

fun3은 가장 가까운 포함 범위 (fun2와 연관된 함수 범위)에서 인스턴스 x를 봅니다. 그러나 fun1 및 전체적으로 정의 된 다른 x 인스턴스는 영향을받지 않습니다.

파이썬에서 2.1 이전 버전과 2.1 이후로 from-future-import를 사용하여 기능을 요청하지 않는 한 nested_scopes 이전에 fun1 및 fun2의 범위는 fun3에 표시되지 않으므로 S.Lott의 답변이 유지되고 전역 x를 얻습니다. :

0 0

1

파이썬에서

값이 할당 된 변수는 할당이 나타나는 블록에 대해 로컬입니다.

현재 범위에서 변수를 찾을 수 없으면 LEGB 순서를 참조하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.