>백엔드 개발 >파이썬 튜토리얼 >Python의 여러 고급 구문 개념에 대한 간략한 분석(람다 표현식 클로저 데코레이터)

Python의 여러 고급 구문 개념에 대한 간략한 분석(람다 표현식 클로저 데코레이터)

高洛峰
高洛峰원래의
2017-01-23 14:38:461514검색

1. 익명 함수
익명 함수는 어떤 식별자에도 바인딩되지 않는 함수를 의미하며 주로 함수형 프로그래밍 언어 분야에서 사용됩니다.
1) 매개변수로 전달됩니다. Python의 내장 함수인 filter/map/reduce와 같은 고차 함수(고차 함수)는 모두 고차 함수의 반환 값인 일반적인 고차 함수입니다
2). 여기서 "값"은 실제로는 함수 객체입니다)
이름이 지정된 함수에 비해 익명 함수는 함수가 한 번만 호출되거나 제한된 횟수로 호출되는 경우 구문적으로 더 가볍습니다.
특정 구문 측면에서 Python은 함수 본문이 람다 구문을 통한 표현식인 익명 함수를 지원합니다. 즉, Python의 람다 표현식은 본질적으로 익명 함수이지만 함수 본문은 표현식만 될 수 있으며 다른 문을 포함할 수 없습니다.
또한 고급 동적 언어에서는 클로저나 데코레이터와 같은 고급 구문을 구현하기 위해 익명 함수를 사용하는 경우가 많습니다.
어떤 경우에는 람다 표현식을 사용하면 Python 프로그램이 매우 간결해 보입니다. 예를 들어, 다음은 값에 따라 dict 요소를 정렬하는 코드 예제입니다:

>>> foo = {'father' : 65, 'mother' : 62, 'sister' : 38, 'brother' : 29, 'me' : 28}
>>> sorted(foo.iteritems(), key=lambda x: x[1])
[('me', 28), ('brother', 29), ('sister', 38), ('mother', 62), ('father', 65)]

2. 클로저
클로저는 본질적으로 참조 환경(참조 환경) 또는 함수 참조를 포함하는 함수입니다. 여기서 "참조 환경"은 일반적으로 함수 본문이 액세스하는 비지역 변수에 대한 참조를 저장하는 테이블에 의해 유지됩니다.
C 언어의 함수 포인터와 비교하여 클로저를 사용하면 중첩된 함수가 범위 외부의 비지역 변수에 액세스할 수 있습니다. 이는 변수에 대한 Python 인터프리터의 범위 검색 규칙과 관련이 있습니다(Python은 LEGB의 검색 규칙을 지원합니다. 자세한 내용을 알아보려면 , 범위와 검색 규칙에 대한 자세한 설명은 "파이썬 배우기" 4판 17장을 참고하거나, 빠른 이해를 위해 이 글을 확인하시면 됩니다.
런타임 메모리 할당 모델이 선형 스택에 지역 변수를 생성하는 언어(일반적으로 C 언어 등)의 경우 일반적으로 클로저 지원이 어렵습니다. 이러한 언어의 기본 구현에서는 함수가 반환되면 함수 스택이 재활용되면서 함수에 정의된 지역 변수가 삭제됩니다. 그러나 클로저의 기본 구현에서는 클로저의 수명 주기가 끝날 때까지 클로저가 실행될 때 액세스하려는 비지역 변수가 유효한 상태로 유지되어야 합니다. 즉, 이러한 비지역 변수는 결정된 경우에만 액세스할 수 있습니다. 더 이상 액세스할 수 없습니다. 이러한 변수를 정의하는 함수가 반환될 때가 아니라 사용될 때만 삭제될 수 있습니다. 따라서 클로저를 자연스럽게 지원하는 언어는 일반적으로 가비지 수집을 사용하여 메모리를 관리합니다. gc 메커니즘은 변수가 시스템에 의해 파괴되고 메모리 공간이 더 이상 참조되지 않을 때만 회수되도록 보장하기 때문입니다.
특정 구문 측면에서 클로저는 일반적으로 중첩된 함수 정의를 동반합니다. Python을 예로 들면, 간단한 클로저 예시는 다음과 같습니다.

#!/bin/env python
#-*- encoding: utf-8 -*-
 
def startAt_v1(x):
 def incrementBy(y):
  return x + y 
 print 'id(incrementBy)=%s' % (id(incrementBy))
 return incrementBy
 
def startAt_v2(x):
 return lambda y: x + y 
 
if '__main__' == __name__:
 c1 = startAt_v1(2)
 print 'type(c1)=%s, c1(3)=%s' % (type(c1), c1(3))
 print 'id(c1)=%s' % (id(c1))
  
 c2 = startAt_v2(2)
 print 'type(c2)=%s, c2(3)=%s' % (type(c2), c2(3))

실행 결과는 다음과 같습니다.

id(incrementBy)=139730510519782
type(c1)=<type &#39;function&#39;>, c1(3)=5
id(c1)=139730510519782
type(c2)=<type &#39;function&#39;>, c2(3)=5

위 예시에서 startAt_v1과 startAt_v2는 모두 클로저를 구현합니다. 그 중: v1은 중첩 정의 함수 구현을 사용합니다. v2는 람다 표현식/익명 함수로 구현됩니다.
클로저를 설명하기 위해 v1을 예로 듭니다.
1) startAt_v1 함수는 1개의 매개변수를 받아들이고 함수 객체를 반환하며, 이 함수 객체의 동작은 중첩된 정의 함수 incrementBy에 의해 구현됩니다.
2) incrementBy 함수의 경우 변수 x는 소위 비지역 변수입니다(x는 함수에 의해 정의된 지역 변수도 아니고 일반적인 의미의 전역 변수도 아니기 때문입니다). incrementBy는 특정 함수 동작을 구현합니다. 반환합니다.
3) 주 입구에서 c1이 받은 반환 값은 함수 객체입니다. id(incrementBy) == id(c1)에서 c1이 "지정한" 객체와 "지정한 객체"라고 결론을 내릴 수 있습니다. 함수 이름 incrementBy의 "to"는 실제로 동일한 하나의 함수 개체입니다.
4) Python의 클로저 지원 덕분에 일반 함수의 객체와 비교하여 c1이 가리키는 객체는 해당 함수 범위 내에 있지 않은 비지역 변수에 액세스할 수 있으며 이 변수는 c1의 외부 래퍼 함수입니다. incrementBy는 startAt_v1의 입력 매개변수에 의해 제공됩니다. 따라서 c1이 가리키는 함수 객체에는 외부 래핑 함수의 입력 매개변수에 대한 "메모리" 함수가 있습니다. 외부 래핑 함수를 호출하여 클로저를 생성할 때 다른 입력 매개변수가 사용됩니다. 내부 기능에 의해 참조 환경으로 유지됩니다.
5) c1(3)을 호출하면 환경 유지를 참조하는 외부 포장 함수의 매개변수와 함께 들어오는 매개변수를 계산하여 최종 결과를 얻습니다.
위의 단계 분석은 생성부터 실행까지 클로저의 기본 원리를 보여줍니다. 이 사례를 이해한 후에는 클로저의 개념도 명확해야 합니다.

3. 데코레이터
파이썬은 데코레이터 구문을 지원합니다. 데코레이터의 개념은 함수형 프로그래밍의 여러 개념(예: 익명 함수 및 클로저)을 포함하기 때문에 초보자에게는 상대적으로 모호합니다. 이것이 이 기사에서 익명 함수 및 클로저를 먼저 소개하는 이유입니다.

我们引用这篇文章对装饰器的定义:
A decorator is a function that takes a function object as an argument, and returns a function object as a return value.
从这个定义可知,装饰器本质上只是一个函数,它借助闭包的语法去修改一个函数(又称被装饰函数)的行为,即decorator其实是个闭包函数,该函数以被装饰函数名(这个函数名其实是一个函数对象的引用)作为入参,在闭包内修改被装饰函数的行为后,返回一个新的函数对象。
特别说明:decorator并非必须以函数形式出现,它可以是任何可被调用的对象,例如它也可以class形式出现,参见这篇文章给出的例子。
在定义好函数装饰器的前提下,当外部调用这个被装饰函数时,decorator的语法糖会由Python解释器解释为先执行装饰器函数,然后在装饰器返回的新函数对象上继续执行其余语句。
来个实例分析一下:

#!/bin/env python
#-*- encoding: utf-8 -*-
 
def wrapper(fn):
 def inner(n, m):
  n += 1
  print &#39;in inner: fn=%s, n=%s, m=%s&#39; % (fn.__name__, n, m)
  return fn(n, m) + 6 // 这里有return且返回值为int对象
 return inner
 
@wrapper
def foo(n, m):
 print &#39;in foo: n=%s, m=%s&#39; % (n, m)
 return n * m
 
print foo(2, 3)

上面的示例中,foo通过@wrapper语法糖声明它的装饰器是wrapper,在wrapper中,定义了嵌套的inner函数(该函数的参数列表必须与被装饰函数foo的参数列表保持一致),装饰器wrapper修改foo的行为后,返回inner(注意:由于inner的返回值是个int对象,故wrpper最终返回的也是个int对象)。
调用foo(2, 3)时,Python解释器先调用wrapper对foo做行为改写,然后返回int对象,不难推测,上述代码的执行结果如下:

in inner: fn=foo, n=3, m=3
in foo: n=3, m=3
foo(2, 3)=15

更多Python的几个高级语法概念浅析(lambda表达式闭包装饰器)相关文章请关注PHP中文网!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.