x = 3
y = [3]
def test1():
x += 1
print x
def test2():
y[0] = 4
y.append(5)
print y
test2()
test1()
这段代码执行结果: test2()成功打印[4, 5], test1()却报错: UnboundLocalError: local variable 'x' referenced before assignment
想不明白,为什么会这样,全局变量在函数里可以直接打印,但是如果要改变它的值,会报错,但是test2()为什么不报错?如果把y换成dict类型,就能在函数里不需要用global声明,可以直接改变y的值,但如果是str或number,就会报错,为什么?
사실 이 질문은 변수가 참조하는 객체가 가변인지 불변인지는 제쳐두어도 됩니다. 우리가 주목해야 할 것은 변수의 위치 , 시점 및 범위입니다. 정의.
다음 코드를 고려하세요.
으아악이 코드는 오류를 발생시킵니다:
으아악a
은test
함수의 param 변수이므로 지역 변수에 속하며, 그 범위는test
함수를 참조하도록 1을 전달하므로 큰 문제는 없습니다.print(a)
과 함께.그런데
b
은 처음부터 끝까지 정의되어 있지 않아서 LEGB 원칙에 따라 검색해도 찾을 수 없어서NameError
을 띄웁니다.이 문제를 해결하기 위해 전역 변수를 정의할 수 있습니다.
으아악좋아 이번에는 문제가 없을 것 같습니다. Python이 전역 범위에서
b
을 찾았기 때문입니다. Python이 전역b
을 사용하는 이유는b
을 로컬에 정의하지 않았기 때문입니다.그런 다음 함수에 변수를 할당하기 시작합니다.
으아악결과:
으아악함수에 있는 두
이 사실은 다음과 같습니다.print
는 1과 20으로 출력되는데, 함수를 떠난 후 출력된b
의 값은 왜 100이 되었나요?함수 A에 이렇게 썼기 때문입니다 할당은 정의
b = 20
이기도 하므로test
에 표시된b
은 전역이 아닌 모두 로컬이므로b
에 대한 변경 사항은 전역 .b
키워드의 도움이 필요합니다:
global
으아악 으아악을 설명하는
좀 더 이해하기 어려운 예를 살펴보겠습니다.global
키워드를 사용하면 Python은b
의test
을 전역b
에 액세스하기 위한 변수로 처리하고b
는 다음과 같이만 처리됩니다. 할당 작업은 새로운 지역 변수.b = 20
으아악
결과:으아악
이 여기에나타납니다. 이유는 매우 간단합니다.
당신이 제시한 예를 되돌아보세요:UnboundLocalError
에는b
함수에 할당 및 정의 작업이 있으므로b = 20
내부의test
는 로컬(전역)입니다. 여기서는b
이 전역임을 나타내기 위해 사용되지 않으므로b
을 사용하면 Python은 전역print(b)
대신 로컬b
을 가져오려고 시도하지만 여기서 비극은 첫 번째 단계에서 로컬b
이 할당되지 않아서 할당되기 전에b
을 참조했다고 하는데 이는 당연히 불가능하다.local variable 'b' referenced before assignment
으아악
여기서
으아악test1
의 정의는x
에 나옵니다(전역은 없고x
은 등호 왼쪽에 나타납니다). 당연히x
을 언급할 때, 로컬을 사용하지만 이유:그래서 등호 오른쪽에 있는
으아악x
에서 참조하는 값을 얻으려면 아직 값이 할당되지 않은 것을 알 수 있습니다. 그러면 위의 예와 같습니다.귀하의
으아악test2
에는 문제가 없습니다.은
결론test2
의 등호 왼쪽에 y가 나오지 않기 때문에 Python은 자동으로 전역y
을 사용한 것으로 가정하므로 당연히 문제가 없습니다.
에 변수 이름이 지정되어 있지 않은지 확인하세요.global
를 추가해야 한다는 점을 기억하세요. 그렇지 않으면 이 작성 방법이 나타나지 않아야 합니다(내부 작업 또는 나중에 할당)
global
(Python3)을 추가하는 것이지만 그것은 또 다른 이야기입니다.
nonlocal
내가 답변한 질문: Python-QA
Python의 변수 범위는 이렇게 규정되어 있습니다. test1에서는
print x
x를 수정할 수는 있지만어떤 사람들은 "로컬 범위의 전역 변수는 읽기 전용이어야 합니다"라고 말하지만, 이는 사실이 아닙니다. 이 조건을 참조하십시오. . .
Python에서 이 부분은 정말 헷갈립니다
간단히 말하면 전역 변수의 바인딩은 로컬 범위에서 변경할 수 없으며 변수의 주소는
CPython
에서 변경할 수 없습니다.참조: 일반적인 실수 4: Python 프로그래머가 저지르는 가장 일반적인 10가지 실수: Python의 변수 이름 구문 분석에 대한 오해
test1
함수에는 Python 인터프리터가 함수의 로컬 범위에 있는 변수로 간주하는 할당 작업x += 1
이 있습니다. 그러나x
변수는 할당 전에 정의되지 않습니다.x
은number
이며 불변 유형에 속합니다. 불변 유형에 새 값을 할당하려면 불변 유형 객체를 다시 만들고 원래 변수를 새로 생성된 객체를 다시 가리켜야 합니다. 새로 생성된 객체는LEGB
에 포함되지 않습니다. 찾을 수 없으므로 오류가 보고됩니다test2
함수에서y
은 변수 유형인list
입니다. 목록은 변수 유형이고 내부에서 수정될 수 있기 때문입니다. , 오류를 보고하지 않습니다Python
의 모든 할당 작업은 기본적으로 다음 세 단계로 구분됩니다(예:a = 3
사용).값을 나타내는 개체 만들기
3
아직 생성되지 않은 경우 변수
a
를 생성합니다.a
변수를 새 개체3
변수의 메모리 주소 변경을 관찰해 보겠습니다. 으아악test2
함수y
실행 중출력
으아악y
이 실제로 수정된 것을 볼 수 있으므로 변수를 반복적으로 생성할 필요가 없으며x
불변 유형의 경우 값을 할당하려면 먼저 새 객체를 생성해야 합니다. 이름이 동일하더라도 매번 다른 할당이 수행되면x
의 메모리 주소가 실제로 다르다는 것을 알 수 있으며 이는str
또는number
이 오류를 보고하는 이유도 설명할 수 있습니다