装饰器,变量在内存的存储与地址变化

函数“变量”(或“变量”函数)

x = 1
y = x
def test1():
    print("Do something")
test2 = lambda x:x*2

函数和变量是一样的,都是“一个名字对应内存地址中的一些内容
那么根据这样的原则,我们就可以理解两个事情:

1.test1表示的是函数的内存地址
2.test1()就是调用对在test1这个地址的内容,即函数


高阶函数

对于高阶函数的形式可以有两种:

1.把一个函数名当作实参传给另外一个函数(“实参高阶函数”)

2.返回值中包含函数名(“返回值高阶函数”)

import time
def test():
    time.sleep(5)
    print('test is running')
def deco(func):
    start=time.time()
    func() #將所有的func换为test   #2
    stop=time.time()
    print(stop-start)
deco(test) #1

在#1处,我们把test当作实参传递给形参func,即func=test。注意,这里传递的是地址,也就是此时func也指向了之前test所定义的那个函数体,可以说在deco()内部,func就是test。在#2处,把函数名后面加上括号,就是对函数的调用(执行它)

import time

def test():
    time.sleep(2)
    print("test is running!")

def deco(func):
    print(func) #<function test at 0x00000270E6524D90>;输出函数地址
    return func #会返回一个test出来,func=test
t = deco(test) #3
t()#4

在#3处,将test传入deco(),在deco()里面操作之后,最后返回了func,并赋值给t。因此这里test => func => t,都是一样的函数体。最后在#4处保留了原来的函数调用方式。
看到这里显然会有些困惑,我们的需求不是要计算函数的运行时间么,怎么改成输出函数地址了。是因为,单独采用第二张高阶函数(返回值中包含函数名)的方式,并且保留原函数调用方式,是无法计时的。如果在deco()里计时,显然会执行一次,而外面已经调用了test(),会重复执行。这里只是为了说明第二种高阶函数的思想


嵌套函数

嵌套函数指的是在函数内部定义一个函数,而不是调用

def fun1():
    def fun2():
        pass
而不是

def fun1():
    fun2()

函数只能调用和它同级别以及上级的变量或函数。也就是说:里面的能调用和它缩进一样的和他外部的,而内部的是无法调用的

import time

def timer(func): #5
    def deco():
        start = time.time()
        func()
        stop = time.time()
        print(stop-start)
    return deco


def test():
    time.sleep(2)
    print("test is running!")


test = timer(test) #6
test() #7

在#6处,把test作为参数传递给了timer(),此时,在timer()内部,func = test,接下来,定义了一个deco()函数,当并未调用,只是在内存中保存了,并且标签为deco。在timer()函数的最后返回deco()的地址deco。
然后再把deco赋值给了test,那么此时test已经不是原来的test了,也就是test原来的那些函数体的标签换掉了,换成了deco。那么在#7处调用的实际上是deco()。
那么这段代码在本质上是修改了调用函数,但在表面上并未修改调用方式,而且实现了附加功能


真正的装饰器

根据以上分析,装饰器在装饰时,需要在每个函数前面加上:

test = timer(test)

显然有些麻烦,Python提供了一种语法糖,即:

@timer

这两句是等价的,只要在函数前加上这句,就可以实现装饰作用


装饰有参函数


  • 转载

Python中变量在内存的存储与地址变化详解(深浅拷贝,值/引用传递、可变不可变数据类型)

https://blog.csdn.net/as480133937/article/details/87305247


  • 转载

https://blog.csdn.net/pdcfighting/article/details/88085534

def sum(a):
    a+=1
a=6
sum(a)
print(a) #6

为什么在这里形参的数值并不改变实参的数值?

这里需要给大家普及一个Python中的基础,在python中,string(字符串), tuples(元组),
和number(数值)是不可更改的对象,而list(列表),dict(字典)等则是可以修改的对象。

也就是说,这里形参的数值对于外部的实参的数值(number类型,不可变)来说是没有任何关系的,他们虽然是同一个名字,但是其指向对象是不一样的。所以当在程序最后进行打印a输出值的时候,其输出仍然是6

list=[1,2,3,4]
temp=list[2]
print(temp) #3;Temp=m[A:B] %表示将m列表里从索引号位置为A开始的元素到B-1处元素之间的列表获取赋给temp

def swap(list):
    temp=list[0] #1
    list[0]=list[1] #list[2,2];  [1,2]的第一位1等于[1,2]的第二位2等于[2,2]
    list[1]=temp #2;[2,2]的第二位等于temp,而temp等于1,所以list=[2,1]
list=[1,2]
swap(list)
print(list) # [2,1]

与第一个栗子刚刚相反,这里形参的数值调用把实参改变了。因为本例中参数传递的是列表,其是可更改的对象,在函数内部经过系列赋值变化之后,所以在程序运行之后其输出值产生了变化

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值