Python의 클로저는 다음과 같이 명시적으로 정의(해석)됩니다. 내부 함수에서 외부 범위(전역 범위가 아님)의 변수가 참조되는 경우 내부 함수는 클로저로 간주됩니다.
다음 지침은 주로 python2.7에 대한 것이며 다른 버전에서는 차이가 있을 수 있습니다.
정의를 직접 보면 명확하지 않을 수도 있습니다. 먼저 내부 기능이 무엇인지 살펴보겠습니다.
def wai_hanshu(canshu_1): def nei_hanshu(canshu_2): # 我在函数内部有定义了一个函数 return canshu_1*canshu_2 return nei_hanshu # 我将内部函数返回出去 a = wai_hanshu(123) # 此时 canshu_1 = 123 print a print a(321) # canshu_2 = 321
함수 안에 중첩된 함수가 있습니다. 외부 함수에 변수를 전달하고 이를 a에 할당하면 a가 함수 객체가 되는 것을 발견하고, 이 함수 객체가 전달되면 다시 매개변수를 사용하면 내부 함수의 반환 값도 얻습니다. 우리는 범위의 원칙에 따라 전역 범위에서 로컬 범위에 접근할 수 없다는 것을 알고 있습니다. 그러나 여기에서는 까다로운 방법을 통해 내부 기능에 액세스합니다. .
계속해서 예를 살펴보겠습니다.
def wai_hanshu(): a = [] def nei_hanshu(canshu): a.append(canshu) return a return nei_hanshu a = wai_hanshu() print a(123) print a(321)
함수는 다음과 같습니다. 외부 함수 목록 a에 있는 내용이 실제로 변경되었습니다. 그 이유를 알려면 먼저 Python 네임스페이스가 무엇인지 알아야 하며, 네임스페이스는 범위 성능의 이유입니다.
네임스페이스를 도입하는 가장 큰 이유는 변수 충돌을 피하기 위해서입니다. 파이썬에는 모듈이 많고, 모듈 안에는 함수, 클래스 등이 있고 모두 변수를 사용하기 때문입니다. 하지만 매번 다른 변수 이름과 충돌하지 않도록 조심해야 한다면 너무 번거로울 것입니다. 개발자는 다른 사람이 작성한 프로그램에서 어떤 변수가 사용되는지 생각하기보다는 자신의 문제에 집중해야 하므로 Python에서는 네임스페이스를 도입했습니다. 네임스페이스는 모듈 레이어로 구분되며, 모듈은 전역 범위와 로컬 범위로 구분됩니다. 다이어그램으로 표현하면
모듈마다 네임스페이스가 다르며, 변수 이름이 충돌하지 않도록 하기 위해 전역 범위와 로컬 범위도 중첩될 수 있습니다. 그런데 __name__ 속성을 통해 네임스페이스의 이름을 얻을 수 있습니다:
메인 파일의 네임스페이스는 '__main__'이라고 하며, 모듈의 네임스페이스는 모듈 이름입니다.
범위는 Python이 변수를 찾을 때 현재 네임스페이스에서 먼저 찾기 때문에 탄생했습니다. 현재 네임스페이스에서 찾을 수 없으면 상위 수준에서 찾습니다. 유추하자면, 결국 찾지 못하면 변수를 찾을 수 없다는 예외가 발생합니다.
우리는 이전에 항상 말했듯이 전역 범위는 로컬 범위에 액세스할 수 없지만 이러한 이유로 로컬 범위는 전역 범위에 액세스할 수 있습니다. 그리고 외부와 동일한 이름으로 로컬 범위에 변수를 생성하면 Python이 이 변수를 찾을 때 먼저 현재 범위에서 해당 변수를 찾습니다. 한 단계 더 높아요.
초기 Python 버전에서는 로컬 범위가 다른 로컬 범위에 액세스할 수 없고 전역 범위에만 액세스할 수 있었습니다. 그러나 현재 버전에서는 한 레벨 위로 순서대로 검색되므로 여기서는 언급하겠습니다.
이 기능 덕분에 내부 함수에서 외부 함수의 변수에 접근할 수 있는데, 이를 클로저라고도 합니다.
참고: 여기에서는 개체를 구분합니다. 예:
def wai_hanshu(): a = [] def nei_hanshu(canshu): a.append(canshu) return a return nei_hanshu a = wai_hanshu() # 我创建了一个对象 b = wai_hanshu() # 我又创建了一个对象 print a print b print a(123) print b(321)
여기에서 wai_hanshu의 연산변수는 모두 a와 b는 완전히 2개의 객체이고, 이들이 위치한 메모리 공간도 다르기 때문에 내부의 데이터도 독립적이다. 내용을 혼동하지 않도록 주의하십시오.
데코레이터
사실 데코레이터는 클로저에 따라 몇 가지 단계를 더 수행합니다.
아아아아在看这段代码的时候,要知道几件事:
1.函数的参数传递的其实是引用,而不是值。
2.函数名也是一个变量,所以可以重新赋值。
3.赋值操作的时候,先执行等号右边的。
只有明白了上面这些事之后,再结合一下代码,应该就能明白什么是装饰器了。所谓装饰器就是在闭包的基础上传递了一个函数,然后覆盖原来函数的执行入口,以后调用这个函数的时候,就可以额外实现一些功能了。装饰器的存在主要是为了不修改原函数的代码,也不修改其他调用这个函数的代码,就能实现功能的拓展。
而python觉得让你每次都进行重命名操作实在太不方便,于是就给出了一个便利的写法:
def zsq(func): def nei(): print '我在传入的函数执行之前做一些操作' func() # 执行函数 print '我在目标函数执行后再做一些事情' return nei @zsq # 自动将其下面的函数作为参数传到装饰函数中去 def login(): print '我进行了登录功能' login()
这些小便利也叫做python的语法糖,你可能在很多地方见过这个说法。
带参数的装饰器:
def zsq(a): print '我是装饰器的参数', a def nei(func): print '我在传入的函数执行之前做一些操作' func() # 执行函数 print '我在目标函数执行后再做一些事情' return nei @zsq('123') def login(): print '我进行了登录功能'
相当于: login = zsq(123)(login) ,所以在这里没有调用就执行了。
装饰器的嵌套:
这里就不完整写个例子了:
@deco1(deco_arg) @deco2 def func(): pass
相当于: func = deco1(deco_arg)(deco2(func))
也就是从上到下的嵌套了。
关于闭包和装饰器就先讲到这里,以后有需要再补充。
以上这篇深入Python의 클로저와 데코레이터 이해하기就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持PHP中文网。
更多Python의 클로저와 데코레이터 이해하기相关文章请关注PHP中文网!