>  기사  >  백엔드 개발  >  Python의 고차 함수 및 함수 데코레이터 분석

Python의 고차 함수 및 함수 데코레이터 분석

黄舟
黄舟원래의
2017-10-01 07:44:271117검색

아래 편집기에서는 Python의 고차 함수와 함수 데코레이터(권장)에 대해 자세히 설명합니다. 편집자님이 꽤 좋다고 생각하셔서 지금 공유하고 모두에게 참고용으로 드리고자 합니다. 편집기를 따라 살펴보겠습니다

1. 이전 섹션 검토

Python 2와 Python 3 사이의 문자 인코딩 문제. Python 프로젝트에 대해 초보자이거나 이미 익숙하더라도 코딩을 하게 될 것입니다. 실수. 여기서 Python3과 Python2의 차이점을 간략하게 요약하겠습니다.

우선 Python3-->코드 파일은 모두 utf-8로 해석됩니다. 코드와 파일을 메모리로 읽어오면 유니코드가 됩니다. 이것이 Python이 인코딩만 하고 디코딩하지 않는 이유입니다. 메모리의 문자 인코딩이 유니코드로 변경되고 유니코드는 "번역"될 수 있는 범용 코드이기 때문입니다. 형식 인코딩 형식. Python3에서는 str과 bytes가 두 가지 형식이고 bytes는 이진 표현으로 사용될 수 있습니다.

Python2는 시스템의 기본 문자 인코딩을 사용하여 코드를 해석하므로 utf-8을 사용하여 코드를 해석하려면 헤더에 이를 선언해야 하며 Python2에는 디코딩 및 인코딩이 있지만 디코딩 작업은 다음과 같습니다. 필요하며 인코딩 작업은 무시될 수 있습니다. 왜냐하면 Python 코드가 메모리에 로드될 때 Python3과 동일한 유니코드이기 때문입니다. Python2에서 주목해야 할 것은 str과 bytes가 동일한 의미를 갖는다는 것입니다. Python2의 str은 Python3의 바이트 형식이고 Python3의 str은 실제로 유니코드입니다.

함수 기준(여기서는 재귀 함수에서 이진 검색을 사용하고 있습니다)

함수를 사용하는 이유: 프로그램은 다음과 같이 설계됩니다. module

정의된 함수에는 세 가지 형태가 있습니다.

- 매개변수 없는 함수

- 매개변수화된 함수

- 빈 함수

PS: 함수에 여러 반환 값이 있는 경우 하나가 반환되었습니다. 데이터 형식은 튜플입니다

- 함수가 매개변수를 전달할 때 매개변수 데이터 형식을 제한하는 방법.

def leon(x:int,y:int)->int:

pass

여기서 x와 y는 여기서 지정되고 int여야 합니다. " -> " 유형은 함수 반환 값도 int여야 함을 의미합니다. Type

print(yan.__annotations__): 형식 매개변수의 제한된 데이터 형식과 반환 값


a = [1,2,3,4,5,7,9,10,11,12,14,15,16,17,19,21] #形参中的num
def calc(num,find_num):
 print(num)
 mid = int(len(num) / 2)   #中间数的下标
 if mid == 0: #递归函数非常重要的判断条件
 if num[mid] == find_num:
  print("find it %s"%find_num)
 else:
  print("cannt find num")
 if num[mid] == find_num: #直接找到不用递归,结束函数
 print("find_num %s"%find_num)
 elif num[mid] > find_num: #find_num应该在左边,向下递归
 calc(num[0:mid],find_num)

 elif num[mid] < find_num: #find_num应该在右边,向下递归
 calc(num[mid+1:],find_num)
calc(a,12)

익명 함수


c = lambda x:x+1 #x就是形参,c就是这个匿名函数的对象

print(c(22))

고차 함수 - 기능

1을 표시합니다. 함수의 메모리 넣기 주소는 매개변수로 다른 함수에 전달됩니다.

2. 함수는 다른 함수를 반환 값으로 반환합니다.


def calc(a,b,c):
print(c(a) + c(b))

calc(-5,10,abs) #引用上一节的实例,将-5和10绝对值相加

2. 고차 함수(보충)

함수는 첫 번째 클래스 객체입니다.

함수를 할당할 수 있습니다.

매개변수로 사용할 수 있습니다.

반환 값으로 사용할 수 있습니다. ​​

컨테이너 유형의 요소로 사용할 수 있습니다.


#函数可以被赋值
def leon():
 print("in the leon")

l = leon
l()

#函数可以被当做参数
def yan(x): #这里x形参,其实就是我们调用实参的函数名
 x() #运行函数

y = yan(leon)


#函数当做返回值
def jian(x): 和上面一样这这也必须传入一个函数
 return x
j = jian(leon) #这里需要注意一点就是这里的意思是运行jian这个函数而这个函数返回的是x 也就是leon这个函数的内存地址,也就是说这时候leon这个函数并没有被执行
j() #运行 leon函数

#可以做为容器类型的元素
leon_dict = {"leon":leon}

leon_dict["leon"]() #这样也可以运行leon这个函数

3 . 클로저 기능

1. 클로저백이란? 공식 웹사이트의 개념을 살펴보고 비교해 보겠습니다. (공식 웹사이트에서 찾은 내용은 아니지만 상관없습니다. 어차피 이해할 수는 없습니다.):

Closure는 Lexical Closure의 약어입니다. . 자유 변수를 참조하는 함수. 참조된 자유 변수는 그것이 생성된 환경을 떠난 후에도 함수에 남아 있습니다. 따라서 클로저는 함수와 관련 참조 환경으로 구성된 엔터티입니다.

혼란스러우신가요? 존재하지 않습니다. 아래에서 간략하게 이야기하겠지만, 한 가지 매우 중요한 것이 있는데, 클로저(Closure)는 데코레이터의 핵심입니다. 예제를 통해 설명하겠습니다


import requests #首先导入一个模块,这个可以不用记

def get(url): #定义一个get函数里面需要传一个url的位置参数
 def wapper(): #在定义一个wapper函数
 res = requests.get(url) #这一步就是打开一个网页
 return res.text #将网页以文字的形式返回
 return wapper #返回最里层的wapper函数

g = get("http://www.baidu.com") #调用:首先因为作用域的原因,我们无法访问到里层的wapper函数,所以我们直接调用get函数这里返回了一个wapper函数
print(g()) # 然后我在调用g(get函数)的对象,这样是不是就访问到里层的wapper函数呢

PS: 여기서는 코드가 위에서 아래로 실행될 때 함수가 호출되지 않으면 함수 내의 코드를 특수 변수로 취급할 수 있습니다. 실행되지 않습니다. 위의 예를 보면, get 함수를 실행하면 wapper 함수의 메모리 주소가 반환되는데 이때는 wapper 함수가 실행되지 않았다는 의미입니다. 는 실제로 wapper입니다. 이는 g만 실행하면 된다는 의미이며, 이는 wapper에서 코드를 실행하는 것과 동일합니다.

4. 함수의 중첩 호출

중첩 호출은 실제로 하나의 함수에서 다른 함수를 호출한 결과이며, 마찬가지로 매우 간단한 부분을 살펴보겠습니다. 코드입니다. 와서 살펴보세요.


#嵌套调用,在一个函数中调用另一个函数的功能
#calc这个函数就是在对比两个数字的大小
def calc2(x,y):
 if x >y :
 return x
 else:
 return y

#我靠老板非常变态,然你直接计算四个数字的大小,擦。
def calc4(a,b,c,d):
 res1 = calc2(a,b) #res1的值,这里不就是calc2这个函数比较时最大的哪一个吗。
 res2 = calc2(res1,c)
 res3 = calc2(res2,d)
 return res3

위의 코드로 메모리를 만듭니다. 중첩 호출은 언제 사용됩니까? 분명히 다른 함수(return의 y 또는 x)의 실행 결과가 필요한 것은 우리 함수(calc4)입니다.

5. 데코레이터(고급 클로저 기능)

다음 코드를 예로 들어보겠습니다. 소스 코드를 변경하지 않고 코드의 실행 시간을 계산하는 방법


def geturl(url):
 response = requests.get(url)
 print(response.status_code)

geturl(http://www.baidu.com)


def timer(func):
 def wapper(url):
 start_time = time.time()
 func(url)
 stop_time = time.time()
 so_time_is = stop_time - start_time
 print("运行时间%s"%so_time_is)
 return wapper


@timer
def geturl(url):
 response = requests.get(url)
 print(response.status_code)

python = geturl(http://www.baidu.com)

그림 코드

装饰器必备:

@timer就是装饰器,意思是装饰它下面的函数,而装饰器和被装饰的都是一个函数。

timer(装饰器函数),首先它会有一个位置参数(func)名字随意,但是必须并且只能是一个位置参数

func参数就是被装饰的geturl这个函数

为什么func是geturl这个函数呢-->上面写了一个装饰器功能:geturl=timer(geturl),我们看到这里的timer中传入的其实就是func函数所以func = geturl(被装饰的函数)

分析geturl=timer(geturl),首先我们可以得知timer这是一个闭包函数,当我们执行这个闭包函数,会把里层的函数(wapper)返回,也就是说timer(geturl)其实就是返回的wapper,所以就可以这样理解了geturl==wapper,所以当我们运行geturl的时候就相当于在执行wapper()这样的一个操作;如果这里实在记不住,就这样。咱上面不是有一个闭包函数吗?你就把geturl=timer(geturl)中的geturl(执行函数的返回结果)当做上面g(函数调用的返回结果),然后在分别再执行了下"g"或者"geturl”这个对象。

如果被装饰者有位置参数的话,我们需要在wapper函数中加上对应的位置参数用来接收,如果长度是不固定的话还可以用*args和**kwargs

六、有参装饰器

听着名字顾名思义,就是在装饰器中还有位置参数。


#一个low得不能再low得验证脚本,如果是显示环境中所有数据必须是由数据库或者一个静态文件提供,并且登录成功时,需要保存用户的一个状态

def auth(auth_type): #有参装饰器名称
 def auth_deco(func): #定义第二层函数名称
 def wrapper(*args,**kwargs): #最里层函数,主要实现认证功能
  if auth_type == "file":
  username = input("username>>:").strip()
  password = input("username>>").strip()
  if username == "leon" and password == "loveleon":
   res = func(*args,**kwargs)
   return res
  elif auth_type == "mysql_auth":
  print("mysql_auth...")
  return func(*args,**kwargs)
 return wrapper #第二层返回的是wrapper函数,其实就是home
 return auth_deco #第一层返回的结果等于第二层函数的名称

@auth(&#39;file&#39;)
def home():
 print("welcome")

home() #执行home-->wrapper

有参函数必备知识:

套路,通过上面无参装饰器,我们得出了geturl=timer(geturl)这个等式。回到有参装饰器,我们又会有什么样子的等式呢?首先@auth("file")是一个装饰器也就是一个函数,所以我们定义了一个auth(auth_type)这个函数,而这个函数返回的是什么呢?没有错就是第二层函数;到了这里我们就会发现@auth("file")其实就是@auth_deco,现在我们知道了现在装饰器其实就是auth_deco,那剩下的还不知道怎么写吗?

整理公式,auth('file')-----------(return)> auth_deco----->@auth_deco ->home=auth_deco(home)

如果记不住?如果实在是记不住,其实就可以这样理解,有参装饰器无非就是在无参装饰器上面加了一层(三层),然后在第一层返回了第二层的函数,而到了第二层就和我们普通用的装饰器是一毛一样了

七、模块导入

import ,创建一个leonyan.py的模块文件,等待被导入


a = 10
b = 20
c = 30

def read1():
 print("in the read1")

def read2():
 print("in the read2")

导入leonyan.py文件(调用模块文件和模块文件在同一目录下)


import leonyan #Python IDE这行会爆红,但是不用管

leonyan.read1() #执行leonyan这个包中的read1函数

leonyan.read2() #执行leonyan这个包中read2函数

print(leonyan.a + leonyan.b + leonyan.c ) #输出60

总结:在Python中包的导入(import ***)会干三个事情:1:创建新的作用域;2:执行该作用域的顶级代码,比如你导入的那个包中有print执行后就会直接在屏幕中输出print的内容;3:得到一个模块名,绑定到该模块内的代码

在模块导入的时候给模块起别名


import leonyan as ly
import pandas as pd #这是一个第三方模块,以后的博客中会写到,这是一个用于做统计的

 

给模块起别名还是挺多的,在有些模块的官方文档中,还是比较推荐这种方法的,比如pandas的官方文档中就是起了一个pd别名,总之as就是一个模块起别名


from *** import ***

from leonyan import read1 #引入直接调用
read1()

 

如果在调用模块的函数作用域中有相同的同名的,会将调用过来的覆盖。

在form ** import ** 中控制需要引用的变量(函数其实在未被执行的时候也是一个存放在内存中的变量)


from leonyan import read1,read2 在同一行中可以引用多个,只需要用逗号隔开就行了

print(read1)
print(read2)
#这里打印的就是read1和read2的内存地址

#需求我现在只需要导入read2

这时候我们就可以在leonyan这个函数中加上这么一行:

__all__ = ["read2"] #这里的意思就是别的文件调用为的时候用from ** import ** 只能拿到read2 这个函数的内存地址,也就是只有read2可以被调用

把模块当做一个脚本执行

我们可以通过模块的全局变量__name__来查看模块名:

当做脚本运行:

__name__ 等于'__main__'

作用:用来控制.py文件在不同的应用场景下执行不同的逻辑

if __name__ == '__main__':


#fib.py

def fib(n): # write Fibonacci series up to n
 a, b = 0, 1
 while b < n:
 print(b, end=&#39; &#39;)
 a, b = b, a+b
 print()

def fib2(n): # return Fibonacci series up to n
 result = []
 a, b = 0, 1
 while b < n:
 result.append(b)
 a, b = b, a+b
 return result

if __name__ == "__main__":
 import sys
 fib(int(sys.argv[1]))

代码执行 Python flb.py 100

只需要简单了解的Python模块导入搜索路径

内建(build-in)  --> sys.path(sys.path是一个列表,而且第一个位置就是当前文件夹)

模块导入的重点-->包的导入

실제 개발 환경에서는 파일의 코드를 끝까지 작성할 수 없습니다. 물론 동일한 폴더에 있는 다른 모듈을 참조할 수도 있지만 이 프로젝트를 혼자서 작성할 수는 없다고 생각한 적이 있습니까? 많은 사람들이 공동으로 개발했습니다. 이로 인해 문제가 발생합니다. 여러 사람이 동일한 컴퓨터를 사용할 수 없으며 동일한 폴더에 함수를 작성하는 것도 불가능합니다. 또한 자체 코드 폴더가 있으며 모든 사람이 인터페이스를 통해 함수를 호출합니다. 이때 이러한 서로 다른 폴더를 호출하는 문제에 직면하게 됩니다. 이런 종류의 문제도 ** import **에서 호출해야 합니다.

위 그림에서는 "module import.py" 폴더를 실행합니다. 먼저 Pythonscript.leonyan.command에서 config를 가져옵니다. 왜냐하면 스크립트를 실행해야 하고 가져오야 할 패키지가 모두 있기 때문입니다. Pythonscript 디렉터리 아래에 있으므로 절대 경로를 통해 직접 가져온 다음 구성 파일을 최종적으로 가져올 때까지 "."을 사용하여 레이어별로 아래로 이동합니다. 가장 바깥쪽 레이어, sys.path 목록의 첫 번째 매개변수가 실행됩니다. 스크립트의 디렉터리입니다. 이는 다른 패키지에서 다른 항목을 호출했다는 의미입니다. 예를 들어 내 config.py가 bing.py 파일을 호출합니다. 이때 절대 경로를 작성해야 합니다. 이는 sys.path 폴더에서 더 이상 찾을 수 없기 때문입니다. 즉, 가져올 수 없습니다.

요약: 패키지 가져오기는 실제로 매우 간단합니다. 한 가지를 기억해야 합니다. Python 내장 모듈을 가져오거나 타사 모듈을 다운로드할 때 직접 작성한 경우 import를 사용하세요. * * import ** 가져오기에는 절대 디렉터리를 사용하면 됩니다. 즉, 호출 스크립트의 상위 디렉터리에서 가져옵니다. 이렇게 하면 모듈 가져오기 오류가 보고되지 않습니다.

위 내용은 Python의 고차 함수 및 함수 데코레이터 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

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