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 == ‘123‘:
            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()

实验结果表明,多个装饰器装饰一个函数,其执行顺序是从下往上。

原文地址:https://www.cnblogs.com/zhaijihai/p/10279332.html

时间: 2024-07-31 20:49:07

Python作用域-->闭包函数-->装饰器的相关文章

函数嵌套 ,名称空间与作用域 ,闭包函数 ,装饰器 ,迭代器, 生成器 三元表达式,列表解析,生成器表达式 递归与二分法, 内置函数

函数嵌套名称空间与作用域闭包函数装饰器迭代器生成器三元表达式,列表解析,生成器表达式递归与二分法内置函数--------------------------------------------函数的嵌套调用:在调用一个函数的过程中,又调用了其他函数函数的嵌套定义:在一个函数的内部,又定义另外一个函数def max(x,y): if x>y: return x else: return ydef max1(a,b,c,d): res=max(a,b) res2=max(res,c) res3=ma

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

一.函数对象 函数(Function)作为程序语言中不可或缺的一部分,但函数作为第一类对象(First-Class Object)却是 Python 函数的一大特性. 那到底什么是第一类对象(First-Class Object)呢? 在 Python 中万物皆为对象,函数也不例外,函数作为对象可以赋值给一个变量.可以作为元素添加到集合对象中.可作为参数值传递给其它函数,还可以当做函数的返回值,这些特性就是第一类对象所特有的. 1.函数身为一个对象,拥有对象模型的三个通用属性:id.类型.和值.

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

一.函数对象 函数(Function)作为程序语言中不可或缺的一部分,但函数作为第一类对象(First-Class Object)却是 Python 函数的一大特性. 那到底什么是第一类对象(First-Class Object)呢? 在 Python 中万物皆为对象,函数也不例外,函数作为对象可以赋值给一个变量.可以作为元素添加到集合对象中.可作为参数值传递给其它函数,还可以当做函数的返回值,这些特性就是第一类对象所特有的. 1.函数身为一个对象,拥有对象模型的三个通用属性:id.类型.和值.

python之闭包函数 装饰器 作业

一:编写函数,(函数执行的时间是随机的) import randomdef t(): time.sleep(random.randrange(1,3)) print('hello')二:编写装饰器,为函数加上统计时间的功能 import timeimport randomdef timebe(func): def wrapper(*args,**kwargs): start_time=time.time() res = func(*args, **kwargs) end_time=time.ti

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

Python函数编程--闭包和装饰器 一.闭包 关于闭包,即函数定义和函数表达式位于另一个函数的函数体内(嵌套函数).而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量.参数.当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包.也就是说,内部函数会在外部函数返回后被执行.而当这个内部函数执行时,它仍然必需访问其外部函数的局部变量.参数以及其他内部函数.这些局部变量.参数和函数声明(最初时)的值是外部函数返回时的值,但也会受到内部函数的影响. def outer(

Python之闭包and装饰器

闭包和装饰器是Python中非常重要的一种语法格式,在日常工作中应用非常广泛. 首先,我先为大家简单的接受一下闭包的概念. 闭包:闭包是在函数嵌套的基础上,内层函数使用到外层函数的变量,且外层函数返回内层函数的引用的一种语法格式. 闭包的基本格式,代码实现: def outer(): num = 0 def inner(): # 使用外部函数的变量 print(num) return inner # 返回inner函数在内存空间中的地址 # 将outer函数的返回值赋值给变量f,也就是说将f指向

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

###############    装饰器的初成和开放封闭原则    ############## # 装饰器 # 装饰器非常重要,面试Python的公司必问, # 原则:开放封闭原则 # # 需求:计算程序执行的时间, import time def func(): start = time.time() time.sleep(0.01) print(123) end = time.time() print(end-start) func() # 这种写法如果有100个函数,你都要加一遍这是

&lt;04day&gt;_函数嵌套--闭包函数--装饰器--迭代器--生成器

一.函数的嵌套定义 1.python函数支持嵌套 def f1(): #f1函数的定义 def f2(): #f2函数的定义 print('from f2') def f3(): #f3函数的定义 print('from f3') f2() f1() 嵌套函数--运行结果说明: 1首先调用f1()结果,f1函数为空.担保函f2函数,f2函数有内容打印并且有调用,f2函数包含f3函数,但f3函数无调用. 运行结果: 列子:多个数据之间的大小比较. #!/usr/bin/python # -*- c

python的闭包及装饰器

闭包: 闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数.这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外.所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体 1.函数是一个对象 2.函数执行完成后内部变量回收 3.函数属性 4.函数的返回值 实例一. 分别检测分数科目总分为100.150两种情况的成绩 初级代码如下: # -*- coding:utf-8 -*- ###检测分数总数为100分的及格情况