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作用域-->闭包函数-->装饰器的更多相关文章

  1. 【Python 函数对象 命名空间与作用域 闭包函数 装饰器 迭代器 内置函数】

    一.函数对象 函数(Function)作为程序语言中不可或缺的一部分,但函数作为第一类对象(First-Class Object)却是 Python 函数的一大特性. 那到底什么是第一类对象(Firs ...

  2. Python记录9:函数4:名称空间作用域+闭包函数+装饰器

    ''' 一: 名称空间namespaces     名称空间就是存放名字与值绑定关系的内存空间 二: 名称空间分为三种     内置名称空间:         1. 特点: 存放是python解释器自 ...

  3. Python函数编程——闭包和装饰器

    Python函数编程--闭包和装饰器 一.闭包 关于闭包,即函数定义和函数表达式位于另一个函数的函数体内(嵌套函数).而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量.参数.当其中一个 ...

  4. Python中利用函数装饰器实现备忘功能

    Python中利用函数装饰器实现备忘功能 这篇文章主要介绍了Python中利用函数装饰器实现备忘功能,同时还降到了利用装饰器来检查函数的递归.确保参数传递的正确,需要的朋友可以参考下   " ...

  5. python之闭包与装饰器

    python闭包与装饰器 闭包 在函数内部定义的函数包含对外部的作用域,而不是全局作用域名字的引用,这样的函数叫做闭包函数. 示例: #-------------------------------- ...

  6. Python--函数对象@命名空间与作用域@包函数@装饰器@迭代器@内置函数

    一.函数对象 函数(Function)作为程序语言中不可或缺的一部分,但函数作为第一类对象(First-Class Object)却是 Python 函数的一大特性. 那到底什么是第一类对象(Firs ...

  7. Python之闭包and装饰器

    闭包和装饰器是Python中非常重要的一种语法格式,在日常工作中应用非常广泛. 首先,我先为大家简单的介绍一下闭包的概念. 闭包:闭包是在函数嵌套的基础上,内层函数使用到外层函数的变量,且外层函数返回 ...

  8. python语法基础-函数-装饰器-长期维护

    ######################################################### # 装饰器 # 装饰器非常重要,面试Python的公司必问, # 原则:开放封闭原则 ...

  9. python 修改的函数装饰器

    把好的代码记录下来 方便以后学习 修改的函数参数装饰器 from functools import wraps import time import logging def warn(timeout) ...

随机推荐

  1. 深入分析DDR(转载)

    深入分析:我们为何需要DDR2内存技术 http://www.cnblogs.com/thx-bj/archive/2008/04/02/1134040.html 文/IT168评测室特约 Myddn ...

  2. Javascript 验证上传图片大小[客户端验证]

    需求分析: 在做上传图片的时候,如果不限制上传图片大小,后果非常的严重.那么我们怎样才可以解决一个棘手的问题呢?有两种方式: 1)后台处理: 也就是AJAX POST提交到后台,把图片上传到服务器上, ...

  3. could not find com.android.support.appcompat-v7:23.4.0

    导入别人的工程到AS中,出现错误,是由于android studio的版本比所加载的工程所使用的版本低,有些包不是最新的. 我的android studio这个包的版本是 v7:23.1.1 所以需要 ...

  4. MyBatis的优缺点

    优点: 1.简单易学 mybatis本身就很小且简单.没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现 ...

  5. 学习:100个高质量Java开发者博客

    谷歌关键字搜索:100个高质量Java开发者博客. Java开发牛人十大必备网站.

  6. Elasticsearch JVM Heap Size大于32G,有什么影响?

    0.引言 在规划ES部署的时候,会涉及到data node的分配堆内存大小,而Elasticsearch默认安装后设置的内存是1GB,对于任何一个业务部署来说,这个都太小了. 设置Heap Size的 ...

  7. pip下载默认绕过代理

    centos7下使用pip7.1.0安装软件,在shell下设置了全局http_proxy和https_proxy,但是每次都遇到网络超时问题, 后来使用pip install xxx --proxy ...

  8. Angular2 兼容 UC浏览器、QQ浏览器、猎豹浏览器

    找到/src/polyfills.ts文件 把/** IE9, IE10 and IE11 requires all of the following polyfills. **/下注释掉的代码恢复 ...

  9. Angular ContentChild

    contentchild // 使用方法 git clone https://git.oschina.net/mumu-osc/learn-component.git cd learn-compone ...

  10. Hadoop日志分析系统启动脚本

    Hadoop日志分析系统启动脚本 #!/bin/bash #Flume日志数据的根文件夹 root_path=/flume #Mapreduce处理后的数据文件夹 process_path=/proc ...