이것은 파이썬이 코드를 바이트 코드로 변환하는 방법과 관련이 있습니다 (컴파일 단계).
함수를 컴파일 할 때 Python은 로컬 변수로 할당 된 모든 변수를 처리하고 최적화를 수행하여 수행해야 할 이름 조회 횟수를 줄입니다. 각 지역 변수에 인덱스가 할당되고 함수가 호출되면 값이 인덱스로 지정된 스택 로컬 배열에 저장됩니다. 컴파일러는 변수에 액세스하기 위해 LOAD_FAST
및 STORE_FAST
opcode를 내 보냅니다.
global
구문은 대신 변수에 값이 할당 되더라도 로컬 변수로 간주되어서는 안되며 인덱스를 할당하면 안된다는 것을 컴파일러에게 알려줍니다. 대신 변수에 액세스하려면 LOAD_GLOBAL
및 STORE_GLOBAL
opcode를 사용합니다. 이러한 연산 코드는 이름을 사용하여 많은 사전 (지역, 전역)에서 조회를 수행하기 때문에 속도가 느립니다.
값을 읽는 변수 만 액세스하는 경우 컴파일러는 로컬 변수 또는 전역 변수인지 여부를 모르기 때문에 항상 LOAD_GLOBAL
을 내고 따라서 전역 변수라고 가정합니다.
첫 번째 함수에서 global x
을 사용하면 x
에 대한 쓰기 액세스를 로컬 변수 대신 전역 변수에 쓰기로 처리하도록 컴파일러에 알립니다. 함수의 연산 코드는 명확하게 :
세 번째 예에서
>>> dis.dis(changeXto1)
3 0 LOAD_CONST 1 (1)
3 STORE_GLOBAL 0 (x)
6 LOAD_CONST 0 (None)
9 RETURN_VALUE
, 당신은 __main__
라는 이름의 지역 변수에 __main__
모듈을 가져온 다음의 x
필드에 할당. 모듈은 모든 최상위 매핑을 필드로 저장하는 객체이므로 __main__
모듈의 변수 x
에 할당합니다. 그리고 찾은 것처럼 코드가 __main__
모듈에 정의되어 있기 때문에 __main__
모듈 필드는 globals()
사전의 값과 직접 매핑됩니다.
>>> dis.dis(changeXto3)
2 0 LOAD_CONST 1 (-1)
3 LOAD_CONST 0 (None)
6 IMPORT_NAME 0 (__main__)
9 STORE_FAST 0 (__main__)
3 12 LOAD_CONST 2 (3)
15 LOAD_FAST 0 (__main__)
18 STORE_ATTR 1 (x)
21 LOAD_CONST 0 (None)
24 RETURN_VALUE
두 번째 예는 재미있다 : 옵 코드는 직접 x
에 액세스하지 않는 것으로 나타났다. x
변수에 값을 할당하므로 컴파일러는 변수가 로컬 변수라고 가정하고 최적화를 수행합니다. 그런 다음 from __main__ import x
은 모듈 __main__
을 가져오고 모듈 __main__
에 x
의 값을 x
이라는 로컬 변수에 바인딩하는 새 바인딩을 만듭니다. 이것은 항상 그렇습니다. from ${module} import ${name}
은 현재 바인딩을 새 네임 스페이스로 만듭니다. 변수 x
에 새 값을 할당하면 관련이없는 모듈 __main__
의 바인딩이 아니라 현재 바인딩이 변경됩니다 (값이 변경 가능하고 변경하면 모든 바인딩을 통해 변경 내용이 표시됨). 여기 옵 코드입니다 :
>>> dis.dis(f2)
2 0 LOAD_CONST 1 (-1)
3 LOAD_CONST 2 (('x',))
6 IMPORT_NAME 0 (__main__)
9 IMPORT_FROM 1 (x)
12 STORE_FAST 0 (x)
15 POP_TOP
3 16 LOAD_CONST 3 (2)
19 STORE_FAST 0 (x)
22 LOAD_CONST 0 (None)
25 RETURN_VALUE
이 생각하는 좋은 방법은 파이썬의 모든 할당은 사전에 값에 이름을 결합하고, 역 참조 그냥 사전 조회를하고있는 것입니다 (이것은 대략적인 근사치입니다 , 개념적 모델에 꽤 가깝다). obj.field
을 수행 할 때 "field"
키의 obj
(obj.__dict__
을 통해 액세스 가능)의 숨겨진 사전을 찾고 있습니다.
네이 키드 변수 이름이있는 경우 locals()
사전에서 찾은 다음 globals()
사전이 다른 경우 (모듈 수준에서 코드가 실행될 때 동일 함) 룩업됩니다. 할당의 경우 global ${name}
(이 구문은 최상위에서 작동 함)을 수행하여 전역 액세스를 원한다고 선언하지 않는 한 항상 바인딩을 locals()
사전에 넣습니다.
그래서 함수를 번역, 이것은 당신이 쓴 경우 거의이다
# NOTE: this is valid Python code, but is less optimal than
# the original code. It is here only for demonstration.
def changeXto1():
globals()['x'] = 1
def changeXto2():
locals()['x'] = __import__('__main__').__dict__['x']
locals()['x'] = 2
def changeXto3():
locals()['__main__'] = __import__('__main__')
locals()['__main__'].__dict__['x'] = 3
changeXto2는 지역 변수를 설정 http://www.saltycrane.com/blog/2008/01/python-variable- scope-notes/ –
modulesimporting 가져 오기에 관한 내용이 없습니다. –