클래스 기반 객체지향 프로그래밍이든, 간단한 함수 내에서 변수를 정의하든, 변수의 범위는 Python 학습에서 항상 이해하고 숙달해야 하는 연결 고리입니다. Python을 시작하는 종합적인 분석부터 시작하겠습니다. 변수의 범위는
전역변수와 지역변수 이해
를 참고하세요. 함수가 처음 등장하는데, = 기호 앞에는 지역변수로 정의되어 있다고 볼 수 있다. 이 경우, 전역 변수에서 변수 이름을 사용하는지 여부와 관계없이 함수에서는 로컬 변수를 사용합니다. 예:
num = 100 def func(): num = 123 print num func()
출력 결과는 123입니다. 함수에 정의된 변수명 num은 지역변수이고 전역변수를 포괄한다는 점을 설명한다. 또 다른 예:
num = 100 def func(): num += 100 print num func()
출력 결과는 다음과 같습니다. UnboundLocalError: 할당 전에 지역 변수 'num'이 참조되었습니다. 오류 메시지: 할당 전에 지역 변수 num이 적용되었습니다. 즉, 변수를 정의하지 않고 잘못 사용하고 있는 것입니다. 이는 여기서 정의한 내용이 전역변수가 아닌 지역변수임을 다시 한 번 증명해 줍니다.
2. 함수 내부에 변수명이 처음 등장하고, = 기호 뒤에 나오며, 이전에 글로벌 변수로 정의된 적이 있다면 여기서는 글로벌 변수를 참조하게 됩니다. 예:
num = 100 def func(): x = num + 100 print x func()
출력 결과는 200입니다. 변수 이름 num이 이전에 전역 변수로 정의되지 않은 경우 다음과 같은 오류 메시지가 나타납니다. 변수가 정의되지 않았습니다. 예:
def func(): x = num + 100 print x func()
출력 결과는 다음과 같습니다. NameError: 전역 이름 'num'이 정의되지 않았습니다.
3. 함수에서 변수를 사용할 때 변수 이름에 전역 변수와 지역 변수가 모두 있으면 기본적으로 지역 변수가 사용됩니다. 예:
num = 100 def func(): num = 200 x = num + 100 prinx x func()
출력 결과는 300입니다.
4. 함수에서 변수를 전역 변수로 정의할 때는 global 키워드를 사용해야 합니다. 예:
num = 100 def func(): global num num = 200 print num func() print num
출력 결과는 각각 200과 200입니다. 이는 함수의 변수 이름 num이 전역 변수로 정의되어 값 200이 할당되었음을 보여줍니다. 또 다른 예:
num = 100 def func(): global num num = 200 num += 100 print num func() print num
출력 결과는 각각 300과 300입니다.
위의 전역 변수와 지역 변수의 적용 시나리오 결과를 바탕으로 입력 필드의 티칭 코드 전반부(중국어 부분에 대한 설명)에 대한 분석을 시도했습니다.
# calculator with all buttons import simplegui # intialize globals store = 0 operand = 0
여기에서 simplegui 모듈이 호출되며 //m.sbmmt.com/에서 오류 없이 동작 가능합니다. 단, Python 환경에서는 이 모듈을 직접 사용할 수 없으며, SimpleGUICS2Pygame 패키지를 먼저 설치해야 합니다.
# event handlers for calculator with a store and operand def output(): """prints contents of store and operand""" print "Store = ", store print "Operand = ", operand print ""
는 정의된 함수 출력()에서 직접 전역 변수 저장 및 피연산자를 사용합니다. 2번 항목을 참고하시면 됩니다.
def swap(): """ swap contents of store and operand""" global store, operand store, operand = operand, store output()
정의된 함수 swap()에서는 전역 변수인 store와 Operand를 먼저 정의합니다. 그렇지 않으면 값을 할당하지 않고 사용한다는 오류 메시지가 나타납니다. 1번 항목을 참고하시면 됩니다. 동시에 다음과 같이 이해해도 될까요: swap() 함수에서 global 키워드가 없을 때 store와 피연산자는 기본 지역 변수이고 = 오른쪽 부분을 사용하는 것은 잘못된 것입니다. 할당 없이. 3번 항목을 참고하시면 됩니다.
def add(): """ add operand to store""" global store store = store + operand output()
여기서 2주 과정 이후 첫 번째 문제에 직면했습니다. 이것이 바로 add() 함수가 store를 정의하지 않고 전역 변수로만 정의하는 이유입니다. 같은 방법으로 피연산자. 이제 1번과 합쳐지면 로컬 변수인 store는 미리 값을 할당하지 않아 직접 사용할 수 없는 반면, 피연산자는 앞서 정의한 글로벌 변수를 직접 호출하여 사용할 수 있기 때문이다.
가변 범위
가변 범위는 Python에서 함정에 빠지기 쉬운 부분입니다.
Python에는 총 4개의 범위가 있습니다.
L(로컬) 로컬 범위
클로저 함수 외부 함수의 E(Enclosing)
G(전역) 전역 범위
B (내장) 내장 범위
는 L --> E --> G --> B의 규칙에 따라 검색됩니다. 즉, 로컬에서 찾을 수 없는 경우 지역외 지역부분(폐쇄 등)을 찾아보실 경우, 다시 못찾으시면 전역검색으로 들어가신 후 내장된 부분으로 이동하시면 됩니다.
Python의 def/class/lambda를 제외하고 if/elif/else/ try/excess for/while과 같은 다른 것들은 범위를 변경할 수 없습니다. 그 안에 정의된 변수는 외부에서 계속 접근할 수 있습니다.
>>> if True: ... a = 'I am A' ... >>> a 'I am A'
if 언어에 정의된 변수 a는 외부에서 여전히 접근 가능합니다.
그러나 def/class/lambda로 래핑되어 내부적으로 할당되면 이 함수/클래스/lambda의 로컬 범위가 된다는 점에 유의하세요.
def/class/lambda 내의 할당은 로컬 범위가 됩니다. 로컬 범위는 전역 범위를 포함하지만 전역 범위에는 영향을 미치지 않습니다.
g = 1 #全局的 def fun(): g = 2 #局部的 return g print fun() # 结果为2 print g # 结果为1
그러나 때로는 함수 내에서 전역 변수를 참조하려는 경우 이를 무시하면 오류가 발생할 수 있습니다.
아아아아这两个函数都会报错UnboundLocalError: local variable 'var' referenced before assignment
在未被赋值之前引用的错误!为什么?因为在函数的内部,解释器探测到var被重新赋值了,所以var成为了局部变量,但是在没有被赋值之前就想使用var,便会出现这个错误。解决的方法是在函数内部添加 globals var 但运行函数后全局的var也会被修改。
闭包Closure
闭包的定义:如果在一个内部函数里,对在外部函数内(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)
函数嵌套/闭包中的作用域:
a = 1 def external(): global a a = 200 print a b = 100 def internal(): # nonlocal b print b b = 200 return b internal() print b print external()
一样会报错- 引用在赋值之前,Python3有个关键字nonlocal可以解决这个问题,但在Python2中还是不要尝试修改闭包中的变量。 关于闭包中还有一个坑:
from functools import wraps def wrapper(log): def external(F): @wraps(F) def internal(**kw): if False: log = 'modified' print log return internal return external @wrapper('first') def abc(): pass print abc()
也会出现 引用在赋值之前 的错误,原因是解释器探测到了 if False 中的重新赋值,所以不会去闭包的外部函数(Enclosing)中找变量,但 if Flase 不成立没有执行,所以便会出现此错误。除非你还需要else: log='var' 或者 if True 但这样添加逻辑语句就没了意义,所以尽量不要修改闭包中的变量。
好像用常规的方法无法让闭包实现计数器的功能,因为在内部进行 count +=1 便会出现 引用在赋值之前 的错误,解决办法:(或Py3环境下的 nonlocal 关键字)
def counter(start): count =[start] def internal(): count[0] += 1 return count[0] return internal count = counter(0) for n in range(10): print count() # 1,2,3,4,5,6,7,8,9,10 count = counter(0) print count() # 1
由于 list 具有可变性,而字符串是不可变类型。
locals() 和 globals()
globals()
global 和 globals() 是不同的,global 是关键字用来声明一个局部变量为全局变量。globals() 和 locals() 提供了基于字典的访问全局和局部变量的方式
比如:如果函数1内需要定义一个局部变量,名字另一个函数2相同,但又要在函数1内引用这个函数2。
def var(): pass def f2(): var = 'Just a String' f1 = globals()['var'] print var return type(f1) print f2() # Just a String # <type 'function'>
locals()
如果你使用过Python的Web框架,那么你一定经历过需要把一个视图函数内很多的局部变量传递给模板引擎,然后作用在HTML上。虽然你可以有一些更聪明的做法,还你是仍想一次传递很多变量。先不用了解这些语法是怎么来的,用做什么,只需要大致了解locals()是什么。
可以看到,locals()把局部变量都给打包一起扔去了。
@app.route('/') def view(): user = User.query.all() article = Article.query.all() ip = request.environ.get('HTTP_X_REAL_IP', request.remote_addr) s = 'Just a String' return render_template('index.html', user=user, article = article, ip=ip, s=s) #或者 return render_template('index.html', **locals())
更多从局部变量和全局变量解析Python中变量的作用域相关文章请关注PHP中文网!