Python全栈开发实战学习5

函数进阶

名称空间

又称name space,顾名思义就是存放名字的地方,存放什么名字呢?举例说明,若变量x=1,1存放于内存,那名字x存放在哪里呢?名称空间正式存放名字x与1绑定关系的地方
名称空间共有3种,分别如下:

  • locals:是函数内的名称空间,包括局部变量和形参
  • globals:全局变量,函数定义所在模块的名字空间
  • builtins:内置模块的那字空间

不同变量的作用域不同正是由这个变量所在的命名空间决定的。

作用域即范围:

  • 全局范围:全局存活,全局有效
  • 局部范围:临时存活,局部有效

查看作用域的方法 globals(),locals()

作用域查找顺序
level = 'L0'
n = 22

def func():
    level = 'L1'
    n = 33
	print(locals())
    def outer():
        n = 44
        level = 'L2'
        print(locals(),n)

        def inner():
            level = 'L3'
            print(locals(), n) # 此处打印的n是多少
        inner()
    outer()

func()

结果
{'level': 'L1', 'n': 33}
({'n': 44, 'level': 'L2'}, 44)
({'n': 44, 'level': 'L3'}, 44)

加载顺序:内置名称空间------>全局名称空间----->局部名称空间
名字的查找顺序:局部名称空间------>全局名称空间----->内置名称空间

inner()里打印的n值是多少?
inner()是嵌套在outer()里面的,inner()中未定义n,但是outer()中有定义n=44,对于inner()来说n是outer()中的全局变量,也就是说n的作用域是整个outer()。

闭包

在一些语言中,在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包。闭包可以用来在一个函数与一组“私有”变量之间创建关联关系。在给定函数被多次调用的过程中,这些私有变量能够保持其持久性。—— 维基百科
详细参考:https://blog.csdn.net/sc_lilei/article/details/80464645
闭包函数的必要条件:

  • 闭包函数必须返回一个函数对象
  • 闭包函数返回的那个函数必须引用外部变量(一般不能是全局变量),而返回的那个函数内部不一定要return
def outer():
    a = 1   #外部函数
    def inner():
        print(a)  #内部函数
    inner()
    print(inner.__closure__)
outer()
print(outer.__closure__)

结果
1
(<cell at 0x00000205587BE918: int object at 0x00007FFF717CE350>,)  # 证明inner()是外包
None   # 证明outer()不是闭包

闭包的作用就是减少函数调用时外部函数相同代码的执行次数,比如每次调用outer()函数时,都会创建一次a=1,如果利用下面的方法可以直接调用内部函数,不用每次都创建a=1。

def outer():
    a = 1
    def inner():
        print(a)
    return inner  # 返回inner()函数的地址
inn = outer()  # inn接收inner()函数地址,并作为对象
inn()  # 调用对象
print(inn.__closure__)

结果
1
(<cell at 0x00000213C056E918: int object at 0x00007FFF5E5AE350>,)

闭包——初试爬虫

# import urllib
from urllib.request import urlopen

def func():
    url = "http://www.xiaohuar.com/"
    def inner():
        ret = urlopen(url).read()
        print(ret)
    return inner

get_func = func()
get_func()

装饰器

装饰器形成的过程

用一个例子来说明。公司绩效考核时老板要看每个员工所写代码的执行时间,要求写一个函数来计算时间
最先想到的是这样的写法:

import time   # 导入time模块
def timer():
    start = time.time()  # 记录开始时间
    time.sleep(0.1) # 用来延时以便显示时间
    print("大家好!")
    end = time.time()   # 记录结束时间
    return end-start

t = timer()
print(t)

虽然能够成功计算出执行时间,不过问题来了,假设有很多个函数,
总不能每个函数体中都加上start------end这个部分吧。就又想了一招:

import time
def func():
    time.sleep(0.1)
    print("大家好!")

def timer(f):
    start = time.time()
    f()
    end = time.time()
    return end - start

t = timer(func)
print(t)

成功地解决了穿“统一服装”的问题,这时人家又会想,timer()是个神马玩意,我只想看func()的执行时间,不想用timer(),那怎么办?
那我们可以让调用func的时候实际调用的是timer,是不是和闭包有点联系呢!

import time
def func():
    time.sleep(0.1)
    print("大家好!")

def timer(f):
    def inner():
        start = time.time()
        f()
        end = time.time()
        print(end - start)
    return inner

func = timer(func)
func()

在这里插入图片描述

装饰器的作用

  • 不想修改函数的调用方式,但是还是想在原来的函数前后添加功能
  • timer()就是一个装饰器函数,只是对一个函数有一些装饰作用

原则:开放封闭原则

  • 开放:对扩展是开放的
  • 封闭:对修改是封闭的

装饰器的固定模式

首先介绍一个习惯用语——语法糖,即“@装饰器函数名”,要紧挨着被装饰函数

import time
def timer(f):
    def inner():
        start = time.time()
        f()
        end = time.time()
        print(end - start)
    return inner

@timer # 相当于func = timer(func),紧挨着被装饰函数func()
def func():
    time.sleep(0.1)
    print("大家好!")
# func = timer(func)
func()

做一些修改,再深入理解一下

import time
def timer(f):
    def inner():
        start = time.time()
        f()
        end = time.time()
        print(end - start)
    return inner

@timer # 相当于func = timer(func),紧挨着被装饰函数func()
def func():
    time.sleep(0.1)
    print("大家好!")
    return "123"
# func = timer(func)
ret = func()
print(ret)

结果
大家好!
0.10089230537414551
None   

为什么没有返回值123呢?因为装饰器@timer,相当于执行func = timer(func),此时的func相当于inner,inner是没有返回值的,所以ret收到的是None。再改一下:

import time
def timer(f):
    def inner():
        start = time.time()
        ret = f()
        end = time.time()
        print(end - start)
        return ret
    return inner

@timer # 相当于func = timer(func),紧挨着被装饰函数func()
def func():
    time.sleep(0.1)
    print("大家好!")
    return "123"
# func = timer(func)
ret = func()
print(ret)

结果
大家好!
0.10078144073486328
123

此时就有了123,因为在inner()中有了返回值ret
接下来学习一下装饰带参数函数的装饰器,注意a的位置

import time
def timer(f):
    def inner(a):
        start = time.time()
        ret = f(a)
        end = time.time()
        print(end - start)
        return ret
    return inner

@timer # 相当于func = timer(func),紧挨着被装饰函数func()
def func(a):
    time.sleep(0.1)
    print("大家好!", a)
    return "123"
# func = timer(func)
ret = func(1)
print(ret)

结果
大家好! 1
0.10086464881896973
123

还没完,看看多个参数怎么办?

import time
def timer(f):
    def inner(*args):  # 这里就用到了不固定传参方式
        start = time.time()
        ret = f(*args)  # 这里就用到了不固定传参方式
        end = time.time()
        print(end - start)
        return ret
    return inner

@timer # 相当于func = timer(func),紧挨着被装饰函数func()
def func1(a):
    time.sleep(0.1)
    print("大家好!", a)
    return "123"
@timer # 相当于func = timer(func),紧挨着被装饰函数func()
def func2(a, b):
    time.sleep(0.1)
    print("大家好!", a, b)
    return "123"
# func = timer(func)
ret1 = func1(1)
ret2 = func2(1,2)
print(ret1, ret2)

结果
大家好! 1
0.10072922706604004
大家好! 1 2
0.10012173652648926
123 123
固定模式
def wrapper(func):   # wrapper装饰器,func=qqxing
	def inner(*args,**kwargs):
		ret = func(*args,**kwargs)
		return ret
	return inner
@wrapper   # 相当于qqxing=wrapper(qqxing)
def qqxing():
	print('123')
ret = qqxing()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值