Python作用域-->闭包函数-->装饰器
1.作用域:
在python中,作用域分为两种:全局作用域和局部作用域。
全局作用域是定义在文件级别的变量,函数名。而局部作用域,则是定义函数内部。
关于作用域,我要理解两点:a.在全局不能访问到局部定义的变量 b.在局部能够访问到全局定义的变量,但是不能修改全局定义的变量(当然有方法可以修改)
下面我们来看看下面实例:
- x = 1
- def funx():
- x = 10
- print(x) # 打印出10
- funx()
- print(x) # 打印出1
如果局部没有定义变量x,那么函数内部会从内往外开始查找x,如果没有找到,就会报错
- x = 1
- def funx():
- print(x) # 打印出1
- funx()
- print(x) # 打印出1
- x = 1
- def funx():
- def func1():
- print(x) # 打印出1
- func1()
- funx()
- print(x) # 打印出1
因此,关于作用域的问题,只需要记住两点就行:全局变量能够被文件任何地方引用,但修改只能在全局进行操作;如果局部没有找到所需的变量,就会往外进行查找,没有找到就会报错。
2.关于高级函数
我们知道,函数名其实就是指向一段内存空间的地址,既然是地址,那么我们可以利用这种特性来。
2.1函数名可以作为一个值
- def delete(ps):
- import os
- filename = ps[-1]
- delelemetns = ps[1]
- with open(filename, encoding='utf-8') as f_read,\
- open('tmp.txt', 'w', encoding='utf-8') as f_write:
- for line in iter(f_read.readline, ''):
- if line != '\n': # 处理非空行
- if delelemetns in line:
- line = line.replace(delelemetns,'')
- f_write.write(line)
- os.remove(filename)
- os.rename('tmp.txt',filename)
- def add(ps):
- filename = ps[-1]
- addelemetns = ps[1]
- with open(filename, 'a', encoding='utf-8') as fp:
- fp.write("\n", addelemetns)
- def modify(ps):
- import os
- filename = ps[-1]
- modify_elemetns = ps[1]
- with open(filename, encoding='utf-8') as f_read, \
- open('tmp.txt', 'w', encoding='utf-8') as f_write:
- for line in iter(f_read.readline, ''):
- if line != '\n': # 处理非空行
- if modify_elemetns in line:
- line = line.replace(modify_elemetns, '')
- f_write.write(line)
- os.remove(filename)
- os.rename('tmp.txt', filename)
- def search(cmd):
- filename = cmd[-1]
- pattern = cmd[1]
- with open(filename, 'r', encoding="utf-8") as f:
- for line in f:
- if pattern in line:
- print(line, end="")
- else:
- print("没有找到")
- dic_func ={'delete': delete, 'add': add, 'modify': modify, 'search': search}
- while True:
- inp = input("请输入您要进行的操作:").strip()
- if not inp:
- continue
- cmd_1 = inp.split()
- cmd = cmd_1[0]
- if cmd in dic_func:
- dic_func[cmd](cmd_1)
- else:
- print("Error")
2.2函数名可以作为返回值
- def outer():
- def inner():
- pass
- return inner
- s = outer()
- print(s)
- ######输出结果为#######
- <function outer.<locals>.inner at 0x000000D22D8AB8C8>
2.3函数名可以作为一个参数
- def index():
- print("index func")
- def outer(index):
- s = index
- s()
- outer(index)
- ######输出结果#########
- index func
所以满足上面两个条件中的一个,都可以称为高级函数.
3.闭包函数
闭包函数必须满足两个条件:1.函数内部定义的函数 2.包含对外部作用域而非全局作用域的引用
下面通过一些实例来说明闭包函数:
实例一:以下仅仅在函数内部定义了一个函数,但并非闭包函数.
- def outer():
- def inner():
- print("inner func excuted")
- inner() # 调用执行inner()函数
- print("outer func excuted")
- outer() # 调用执行outer函数
- ####输出结果为##########
- inner func excuted
- outer func excuted
实例二:以下在函数内部定义了一个函数,而且还引用了一个外部变量x,那么这个是闭包函数么?
答案:不是
- x = 1
- def outer():
- def inner():
- print("x=%s" %x) # 引用了一个非inner函数内部的变量
- print("inner func excuted")
- inner() # 执行inner函数
- print("outer func excuted")
- outer()
- #####输出结果########
- x=1
- inner func excuted
- outer func excuted
在回头来看看对闭包函数的定义,是不是两条都满足?聪明的你,一定发现不满足第二条.对,这里的变量x,是属于全局变量,而非外部作用于域的变量。再来看看下面例子:
- def outer():
- x = 1
- def inner():
- print("x=%s" %x)
- print("inner func excuted")
- inner()
- print("outer func excuted")
- outer()
- #####输出结果#########
- x=1
- inner func excuted
- outer func excuted
现在我们来抽象的定义一下闭包函数。它是函数和与其相关的引用环境组合而成的实体。在实现深约束时,需要创建一个能显式表示引用环境的东西,并将它与相关的子程序捆绑在一起,这样捆绑起成为闭包。在上面实例中,我们可以发现,闭包函数,它必须包含自己的函数以及一个外部变量才能真正称得上是一个闭包函数。如果没有一个外部变量与其绑定,那么這个函数不能算得上是闭包函数。
那么怎么知道一个闭包函数有多少个外部引用变量呢?看看下面代码.
- def outer():
- x = 1
- y = 2
- def inner():
- print("x= %s" %x)
- print("y= %s" %y)
- print(inner.__closure__)
- return inner
- outer()
- ######输出结果#######
- (<cell at 0x000000DF9EA965B8: int object at 0x000000006FC2B440>, <cell at 0x000000DF9EA965E8: int object at 0x000000006FC2B460>)
结果表明,在inner内部,引用了两个外部局部变量。如果引用的是非局部变量,那么这里输出的为None.
闭包函数的特点:1.自带作用域 2.延迟计算
那么闭包函数有什么作用呢?我们清楚的知道,闭包函数在定义时,一定会绑定一个外部环境。這个整体才能算的上是一个闭包函数,那么我们可以利用这个绑定特性,来完成某些特殊的功能。
- def outer():
- x = 1
- y = 2
- def inner():
- print("x= %s" %x)
- print("y= %s" %y)
- print(inner.__closure__)
- return inner
- outer()
- ######输出结果#######
- (<cell at 0x000000DF9EA965B8: int object at 0x000000006FC2B440>, <cell at 0x000000DF9EA965E8: int object at 0x000000006FC2B460>)
结果表明,在inner内部,引用了两个外部局部变量。如果引用的是非局部变量,那么这里输出的为None.
闭包函数的特点:1.自带作用域 2.延迟计算
那么闭包函数有什么作用呢?我们清楚的知道,闭包函数在定义时,一定会绑定一个外部环境。這个整体才能算的上是一个闭包函数,那么我们可以利用这个绑定特性,来完成某些特殊的功能。
实例三:根据传入的URL,来下载页面源码
- from urllib.request import urlopen
- def index(url)
- def get()
- return urlopen(url).read()
- return get
- python = index("http://www.python.org") # 返回的是get函数的地址
- print(python()) # 执行get函数《并且将返回的结果打印出来
- baidu = index("http://www.baidu.com")
- print(baidu())
有人可以会说,这个不满足闭包函数的条件啊!我没有引用非全局的外部变量啊。其实并非如此,给,我们之前说过,只要在函数内部的变量都属于函数。那么我在index(url),这个url也属于函数内部,只不过我们省略一步而已,所以上面那个函数也是闭包函数。
4.装饰器
有了以上基础,对于装饰器就好理解了.
装饰器:外部函数传入被装饰函数名,内部函数返回装饰函数名。
特点:1.不修改被装饰函数的调用方式 2.不修改被装饰函数的源代码
4.1.无参装饰器
有如下实例,我们需要计算一下代码执行的时间。
- import time, random
- def index():
- time.sleep(random.randrange(1, 5))
- print("welcome to index page")
根据装饰器的特点,我们不能对index()进行任何修改,而且调用方式也不能变。这时候,我们就可以使用装饰器来完成如上功能.
- import time, random
- def outer(func): # 将index的地址传递给func
- def inner():
- start_time = time.time()
- func() # fun = index 即func保存了外部index函数的地址
- end_time = time.time()
- print("运行时间为%s"%(end_time - start_time))
- return inner # 返回inner的地址
- def index():
- time.sleep(random.randrange(1, 5))
- print("welcome to index page")
- index = outer(index) # 这里返回的是inner的地址,并重新赋值给index
- index()
但是,有些情况,被装饰的函数需要传递参数进去,有些函数又不需要参数,那么如何来处理这种变参数函数呢?下面来看看有参数装饰器的使用情况.
4.2有参装饰器
- def outer(func): # 将index的地址传递给func
- def inner(*args, **kwargs):
- start_time = time.time()
- func(*args, **kwargs) # fun = index 即func保存了外部index函数的地址
- end_time = time.time()
- print("运行时间为%s"%(end_time - start_time))
- return inner # 返回inner的地址
下面来说说一些其他情况的实例。
如果被装饰的函数有返回值
- def timmer(func):
- def wrapper(*args,**kwargs):
- start_time = time.time()
- res=func(*args,**kwargs) #res来接收home函数的返回值
- stop_time=time.time()
- print('run time is %s' %(stop_time-start_time))
- return res
- return wrapper
- def home(name):
- time.sleep(random.randrange(1,3))
- print('welecome to %s HOME page' %name)
- return 123123123123123123123123123123123123123123
这里补充一点,加入我们要执行被装饰后的函数,那么应该是如下调用方式:
home = timmer(home) # 等式右边返回的是wrapper的内存地址,再将其赋值给home,这里的home不在是原来的的那个函数,而是被装饰以后的函数了。像home = timmer(home)这样的写法,python给我们提供了一个便捷的方式------语法糖@.以后我们再要在被装饰的函数之前写上@timmer,它的效果就和home = timmer(home)是一样的。
如果一个函数被多个装饰器装饰,那么执行顺序是怎样的。
- import time
- import random
- def timmer(func):
- def wrapper():
- start_time = time.time()
- func()
- stop_time=time.time()
- print('run time is %s' %(stop_time-start_time))
- return wrapper
- def auth(func):
- def deco():
- name=input('name: ')
- password=input('password: ')
- if name == 'egon' and password == '':
- print('login successful')
- func() #wrapper()
- else:
- print('login err')
- return deco
- @auth # index = auth(timmer(index))
- @timmer # index = timmer(index)
- def index():
- time.sleep(3)
- print('welecome to index page')
- index()
实验结果表明,多个装饰器装饰一个函数,其执行顺序是从下往上。
Python作用域-->闭包函数-->装饰器的更多相关文章
- 【Python 函数对象 命名空间与作用域 闭包函数 装饰器 迭代器 内置函数】
一.函数对象 函数(Function)作为程序语言中不可或缺的一部分,但函数作为第一类对象(First-Class Object)却是 Python 函数的一大特性. 那到底什么是第一类对象(Firs ...
- Python记录9:函数4:名称空间作用域+闭包函数+装饰器
''' 一: 名称空间namespaces 名称空间就是存放名字与值绑定关系的内存空间 二: 名称空间分为三种 内置名称空间: 1. 特点: 存放是python解释器自 ...
- Python函数编程——闭包和装饰器
Python函数编程--闭包和装饰器 一.闭包 关于闭包,即函数定义和函数表达式位于另一个函数的函数体内(嵌套函数).而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量.参数.当其中一个 ...
- Python中利用函数装饰器实现备忘功能
Python中利用函数装饰器实现备忘功能 这篇文章主要介绍了Python中利用函数装饰器实现备忘功能,同时还降到了利用装饰器来检查函数的递归.确保参数传递的正确,需要的朋友可以参考下 " ...
- python之闭包与装饰器
python闭包与装饰器 闭包 在函数内部定义的函数包含对外部的作用域,而不是全局作用域名字的引用,这样的函数叫做闭包函数. 示例: #-------------------------------- ...
- Python--函数对象@命名空间与作用域@包函数@装饰器@迭代器@内置函数
一.函数对象 函数(Function)作为程序语言中不可或缺的一部分,但函数作为第一类对象(First-Class Object)却是 Python 函数的一大特性. 那到底什么是第一类对象(Firs ...
- Python之闭包and装饰器
闭包和装饰器是Python中非常重要的一种语法格式,在日常工作中应用非常广泛. 首先,我先为大家简单的介绍一下闭包的概念. 闭包:闭包是在函数嵌套的基础上,内层函数使用到外层函数的变量,且外层函数返回 ...
- python语法基础-函数-装饰器-长期维护
######################################################### # 装饰器 # 装饰器非常重要,面试Python的公司必问, # 原则:开放封闭原则 ...
- python 修改的函数装饰器
把好的代码记录下来 方便以后学习 修改的函数参数装饰器 from functools import wraps import time import logging def warn(timeout) ...
随机推荐
- CSS学习笔记(10)--nth-child和nth-of-type
CSS3 :nth-child() 选择器 规定属于其父元素的第二个子元素的每个 p 的背景色: p:nth-child(2) CSS3 :nth-of-type() 选择器 规定属于其父元素的第二个 ...
- am335x -- led 控制
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h&g ...
- oozie中事件触发input-events和done-flag
样例如下: <coordinator-app name="test_job" frequency="${coord:days(1)}" start=&qu ...
- HTML5标准最终来了,看什么书学习最好??????
近期看了一本书<HTML5网页开发实例具体解释>,是大众点评的攻城狮写的,认为非常有收获.看样子眼下大多数的国内网页都支持HTML5了,全栈project师是不是必须得会HTML5? 有兴 ...
- Ubuntu Python 安装numpy SciPy、MatPlotLib环境
安装 sudo apt-get install python-scipysudo apt-get install python-numpysudo apt-get install python-mat ...
- Hibernate Annotations 注解
Hibernate Annotations 注解 对于org.hibernate.annotations与org.hibernate.persistence,它的注释比如Columns,可是不知道怎么 ...
- 滚动到指定位置js
function mScroll(id){ $("html,body").stop(true); $(); }
- asp.net后台cs中的JSON格式变量在前台Js中调用方法(前后台示例代码)
//后台cs代码: using System; using System.Collections.Generic; using System.Linq; using System.Web; using ...
- Pecan
什么是peacn Pecan是一个轻量级的基于Python的Web框架, Pecan的目标并不是要成为一个“full stack”的框架, 因此Pecan本身不支持类似Session和Database ...
- 学习《深入理解C#》—— 委托的构成、合并与删除和总结 (第二章1.1---1.4)
目录 简单委托的构成 合并和删除委托 委托总结 简单委托的构成 委托四部曲: 声明委托类型. 必须有一个方法包含了要执行的方法. 必须创建一个委托实例. 必须调用委托(invoke)实例 ① 声明委托 ...