最近学到 函数 闭包的时候,似懂非懂、迷迷糊糊的样子,很是头疼,今天就特意查了下关于闭包的知识,现将我自己的理解分享如下!

一、python 闭包定义

首先,关于闭包,百度百科是这样解释的:

  闭包是指可以包含自由(未绑定到特定对象)变量的代码块;这些变量不是在这个代码块内或者任何全局上下文中定义的,而是在定义代码块的环境中定义(局部变量)。“闭包” 一词来源于以下两者的结合:要执行的代码块(由于自由变量被包含在代码块中,这些自由变量以及它们引用的对象没有被释放)和为自由变量提供绑定的计算环境(作用域)。

      当然,这种学术性的解释对于我们小白来说,只能是更加的晦涩难懂。

从python对闭包的定义来说:

  必须是内部定义的函数,该函数包含对外部作用域而不是全局作用域名字的引用!

可能这么说还是有点难理解,那咱们换一种方式理解:

  python中的闭包从表现形式上可以解释为:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包.

举个简单的例子来说明,可能会好理解一些:

def f1():
x = 12
def f2():
print(x)
return f2
f = f1()
print(type(f))
print(f)
f()

代码执行之后的结果如下:

<class 'function'>
<function f1.<locals>.f2 at 0x00000000028EC9D8>
12

结合这段简单的代码和定义来说明闭包:
如果在一个内部函数里:f2()就是这个内部函数,
对在外部作用域(但不是在全局作用域)的变量进行引用:x就是被引用的变量,x在外部作用域f1()里面,但不在全局作用域里。
则这个内部函数f2()就是一个闭包。

  从函数的定义角度出发:函数可以嵌套使用,可以把函数当成参数或返回值进行传递,函数也可以作为容器类型的元素,作为一个变量可以去赋值。

  在这个简单的例子当中,函数f1()中嵌套定义另一个函数f2(),内部的函数f2()引用了外部函数f1()的变量,函数f2()被当成夹带外部变量的 对象 返回给f1(),这样就形成一个闭包函数。

  实例化输出的时候 定义的 f=f1()中, 其实 f 就是函数f2()(不准确但是好理解)。这里需要注意的是,f 是一个函数名,加上()就能当作函数来用了。(因为f2()返回的是一串函数执行过程的包)

二、闭包的用途

1、闭包就是为了不动原函数里面的代码,还要给它增加‘新功能’的一种手段。

  最直接的例子就是爬取网站代码的闭包函数,不使用的时候,不用执行闭包函数,当需要爬取网站数据时,直接将定义的函数名后加上(),当作函数来使用。

 1 from urllib.request import urlopen
 2 def get(url):
 3     def index():
 4         return urlopen(url).read()
 5     return index
 6 
 7 python=get('http://www.python.org')
 8 print(python)   #主函数的内存
 9 print(python())  #查看爬取网址之后,获得的网址的具体内容
10 print(python.__closure__[0].cell_contents)  #将下载下来的内容翻译,以网址的形式显示下载的网站。

执行结果如下:

<function get.<locals>.index at 0x0000000002E45B70>
b'<!doctype html>\n<!--[if lt IE 7]>   <html class="no-js ie6 lt-ie7 lt-ie8 lt-ie9">   <![endif]-->\n<!--[if IE 7]>      <html class="no-js ie7 lt-ie8 lt-ie9">          <![endif]-->\n<!--[if IE 8]>      <html class="no-js ie8 lt-ie9">                 <![endif]-->\n<!--[if gt IE 8]><!--><html class="no-js" lang="en" dir="ltr">  <!--<![endif]-->\n\n<head>\n    <meta charset="utf-8">\n    <meta http-equiv="X-UA-Compatible" content="IE=edge">\n\n    <link rel="prefetch" href="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js">\n\n    <meta name="application-name" content="Python.org">\n    <meta name="msapplication-tooltip" content="The official home of the Python Programming Language">\n    <meta name="apple-mobile-web-app-title" content="Python.org">\n    <meta name="apple-mobile-web-app-capable" content="yes">\n    <meta name="apple-mobile-web-app-status-bar-style" content="black">\n\n    <meta name="viewport" content="width=device-width, initial-scale=1.0">\n    <meta name="HandheldFriendly" content="True">\n    <meta name="format-detection" content="telephone=no">\n    <meta http-equiv="cleartype" content="on">\n    <meta http-equiv="imagetoolbar" content="false">\n\n    <script src="/static/js/libs/modernizr.js"></script>\n\n    <link href="/static/stylesheets/style.css" rel="stylesheet" type="text/css" title="default" />\n    <link href="/static/stylesheets/mq.css" rel="stylesheet" type="text/css" media="not print, braille, embossed, speech, tty" />\n    \n\n    <!--[if (lte IE 8)&(!IEMobile)]>\n    <link href="/static/stylesheets/no-mq.css" rel="stylesheet" type="text/css" media="screen" />\n    \n    \n    <![endif]-->\n\n    \n    <link rel="icon" type="image/x-icon" href="/static/favicon.ico">\n    <link rel="apple-touch-icon-precomposed" sizes="144x144" href="/static/apple-touch-icon-144x144-precomposed.png">\n    <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/static/apple-touch-icon-114x114-precomposed.png">\n    <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/static/apple-touch-icon-72x72-precomposed.png">\n    <link rel="apple-touch-icon-precomposed" href="/static/apple-touch-icon-precomposed.png">\n    <link rel="apple-touch-icon" href="/static/apple-touch-icon-precomposed.png">\n\n    \n    <meta name="msapplication-TileImage" content="/static/metro-icon-144x144-precomposed.png"><!-- white shape -->\n    <meta name="msapplication-TileColor" content="#3673a5"><!-- python blue -->\n    <meta name="msapplication-navbutton-color" content="#3673a5">\n\n    <title>Welcome to Python.org</title>\n\n    <meta name="description" content="The official home of the Python Programming Language">\n    <meta name="keywords" content="Python programming language object oriented web free open source software license documentation download community">\n\n    \n    <meta property="og:type" content="website">\n    <meta property="og:site_name" content="Python.org">\n    <meta property="og:title" content="Welcome to Python.org">\n    <meta property="og:description" content="The official home of the Python Programming Language">\n    \n    <meta property="og:image" content="https://www.python.org/static/opengraph-icon-200x200.png">\n    <meta property="og:image:secure_url" content="https://www.python.org/static/opengraph-icon-200x200.png">\n    \n    <meta property="og:url" content="https://www.python.org/">\n\n    <link rel="author" href="/static/humans.txt">\n\n    \n\n    \n    <script type="application/ld+json">\n     {\n       "@context": "http://schema.org",\n       "@type": "WebSite",\n       "url": "https://www.python.org/",\n       "potentialAction": {\n         "@type": "SearchAction",\n         "target": "https://www.python.org/search/?q={search_term_string}",\n         "query-input": "required name=search_term_string"\n       }\n     }\n    </script>\n\n    \n    <script type="text/javascript">\n    var _gaq = _gaq || [];\n    _gaq.push([\'_setAccount\', \'UA-39055973-1\']);\n    _gaq.push([\'_trackPageview\']);\n\n    (function() {\n        var ga = document.createElement(\'script\'); ga.type = \'text/javascript\'; ga.async = true;\n        ga.src = (\'https:\' == document.location.protocol ? \'https://ssl\' : \'http://www\') + \'.google-analytics.com/ga.js\';\n        var s = document.getElementsByTagName(\'script\')[0]; s.parentNode.insertBefore(ga, s);\n    })();\n    </script>\n    \n</head>\n\n<body class="python home" >
http://www.python.org

 

2、通过外面的一层层的函数传递的参数,让最内层的函数可以直接调用外层函数所有参数,从而实现不动原函数的代码,增加新功能的办法。

  在python中,最恰当的例子就是装饰器!不动源代码,通过装饰器给源代码加上新的功能!

 1 import time
 2 
 3 def timer(func):
 4     def wrapper(*args,**kwargs):
 5         start_time = time.time()
 6         func(*args,**kwargs)
 7         stop_time = time.time()
 8         print("run time is %s"%(stop_time-start_time))
 9     return wrapper
10 
11 @timer
12 def index():  #index = timer(index)
13     time.sleep(1.5)
14     print("welcome to beijing!")
15 
16 @timer
17 def home(name):
18     time.sleep(1)
19     print("welcome to %s home page"%name)
20 
21 @timer
22 def auth(name,passwd):
23     time.sleep(0.5)
24     print(name,passwd)
25 
26 @timer
27 def tell():
28     print("---***---")
29 
30 index()
31 home("alex")
32 auth("alex","alex3714")
33 tell()

执行结果如下:

welcome to beijing!
run time is 1.5000858306884766
welcome to alex home page
run time is 1.0000572204589844
alex alex3714
run time is 0.5000283718109131
---***---
run time is 0.0

 

相关文章: