[python] 범위 지정 규칙에 대한 간단한 설명?
파이썬 범위 규칙은 정확히 무엇입니까 ?
코드가있는 경우 :
code1
class Foo:
code2
def spam.....
code3
for code4..:
code5
x()
어디서 x
찾을 수 있습니까? 가능한 목록은 다음과 같습니다.
- 둘러싸는 소스 파일에서
- 클래스 네임 스페이스에서
- 함수 정의에서
- for 루프 인덱스 변수에서
- for 루프 내부
또한 함수 spam
가 다른 곳으로 전달 될 때 실행 중에 컨텍스트 가 있습니다. 람다 함수 가 약간 다르게 전달 될 수 있습니까?
어딘가에 간단한 참조 또는 알고리즘이 있어야합니다. 중간 파이썬 프로그래머에게는 혼란스러운 세상입니다.
답변
실제로, 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 참조 ).
답변
본질적으로 파이썬에서 새로운 범위를 소개하는 유일한 것은 함수 정의입니다. 클래스는 본문에 직접 정의 된 항목이 클래스의 네임 스페이스에 배치되지만 포함 된 메서드 (또는 중첩 클래스)에서 직접 액세스 할 수 없다는 점에서 약간 특별한 경우입니다.
귀하의 예에는 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
전역 키워드 와 유사한 방식으로 동작하지만 중첩 된 함수 범위에 대해 ” ” 라는 새로운 키워드를 도입했습니다 .
답변
Python3 시간에 대한 완전한 대답은 없었으므로 여기서 대답했습니다. 여기에 설명 된 대부분의 내용은 4.2.2 Python 3 문서 이름 확인에 자세히 설명되어 있습니다.
다른 답변에서 제공하는 것처럼 로컬, 인클로저, 글로벌 및 내장에 대한 4 가지 기본 범위 인 LEGB가 있습니다. 이외에도 클래스 범위 내에 정의 된 메소드의 엔 클로징 범위를 포함하지 않는 특수 범위 인 클래스 본문이 있습니다 . 클래스 본문 내에서 할당하면 변수가 클래스 본문에 바인딩됩니다.
특히 및 이외의 블록 문 은 변수 범위를 만들지 않습니다 . 파이썬 2에서는리스트 이해가 변수 범위를 생성하지 않지만, 파이썬 3에서는리스트 이해 내의 루프 변수가 새로운 범위로 생성됩니다.def
class
학급의 특성을 보여주기 위해
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
기능이 내장 매크로에서 조회 할.
답변
Python 2.x의 범위 지정 규칙은 이미 다른 답변에 설명되어 있습니다. 내가 추가 할 유일한 것은 Python 3.0에는 로컬이 아닌 범위 ( ‘nonlocal’키워드로 표시됨)의 개념이 있다는 것입니다. 이를 통해 외부 스코프에 직접 액세스 할 수 있으며 어휘 클로저 (가변 객체를 포함하는 추악한 해킹없이)를 포함한 깔끔한 트릭을 수행 할 수 있습니다.
편집 : 여기에 대한 자세한 정보 가있는 PEP 가 있습니다.
답변
범위의 약간 더 완전한 예 :
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
답변
파이썬은 일반적으로 세 가지 네임 스페이스로 변수를 해결합니다.
실행 중 언제든지 네임 스페이스에 직접 액세스 할 수있는 중첩 된 범위가 세 개 이상 있습니다. 가장 먼저 검색되는 가장 안쪽 범위에는 로컬 이름이 포함됩니다. 가장 가까운 엔 클로징 범위에서 시작하여 검색되는 모든 엔 클로징 함수의 네임 스페이스 다음에 검색되는 중간 범위에는 현재 모듈의 전역 이름이 포함됩니다. 가장 바깥 쪽 범위 (마지막으로 검색)는 내장 이름이 포함 된 네임 스페이스입니다.
이 두 가지 기능은 다음과 같습니다 globals
과 locals
내용 당신에게 이러한 네임 스페이스의 두 가지를 표시한다.
네임 스페이스는 패키지, 모듈, 클래스, 객체 구성 및 기능으로 생성됩니다. 다른 이름 공간은 없습니다.
이 경우 이름 지정된 함수에 대한 호출 x
은 로컬 네임 스페이스 또는 글로벌 네임 스페이스에서 해결되어야합니다.
이 경우 로컬은 메소드 함수의 본문입니다 Foo.spam
.
글로벌은 글로벌입니다.
규칙은 메소드 함수 (및 내포 된 함수 정의)로 작성된 내포 된 로컬 공간을 검색 한 후 글로벌을 검색하는 것입니다. 그게 다야.
다른 범위는 없습니다. for
문 (와 같은 다른 복합 명령문 if
과는 try
) 새로운 중첩 된 범위를 작성하지 않습니다. 정의 (패키지, 모듈, 함수, 클래스 및 객체 인스턴스)
클래스 정의 내에서 이름은 클래스 네임 스페이스의 일부입니다. code2
예를 들어, 클래스 이름으로 규정되어야합니다. 일반적으로 Foo.code2
. 그러나 self.code2
파이썬 객체는 포함하는 클래스를 폴백으로 간주하기 때문에 작동합니다.
객체 (클래스의 인스턴스)에는 인스턴스 변수가 있습니다. 이러한 이름은 객체의 네임 스페이스에 있습니다. 그것들은 객체에 의해 자격이 있어야합니다. ( variable.instance
)
수업 방법 내에서 지역과 세계가 있습니다. self.variable
인스턴스를 네임 스페이스로 선택 한다고 말합니다 . 이것이 self
모든 클래스 멤버 함수에 대한 인수이므로 로컬 네임 스페이스의 일부가됩니다.
Python 범위 규칙 , Python 범위 , 변수 범위를 참조하십시오 .
답변
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