标题作用域
标题函数即对象:
在python世界里,函数和我们之前的[1,2,3],‘abc’,8等一样都是对象,而且函数是最高级的对象(对象例化,
可以调用相应的方法,函数是包括变量对象的对象)。
在这里插入代码片
def foo():
print('i am the foo')
bar()
def ber():
print('i am the bar')
foo()
def bar(): #报错
print('i am the bar')
带着这个问题,我们聊聊函数在内存的储存情况:
函数对象的调用仅仅比其他对象多了一个()而已!foo,bar与a,b一样都是个变量名。
那上面的问题也解决了,只有函数加载到内存才可以被调用。
1.作用域: L_E_G_B
在这里插入代码片X=10
def f():
a=5
def inner():
a=7
print a
peturn 1
2.高阶函数
1.函数名可以作为参数输入
2.函数名可以做为反回值
3.闭包 :
在这里插入代码片def outer():
x=10
def inner():# 条件一 inner 就是内部函数
print(x)# 条件2 外部环境的一个变量
return inner # 结论:内部函数inner就是一个闭包
outer()()
f=outer()
f()
inner() # 局部变量,全局无法调用
f=outer()
f()
def inner():
print(x)
import time
start=time.time()
time.sleep(1)
end=time.time()
print(end-start)# 1.0011885166168213
print(start) # 1574173303.6451259
遵守开放封闭原则
在这里插入代码片def foo():
print('foo....')
time.slepp(2)
def bar():
print('bar.....')
time.sleep(3)
def show_time(f):
start = time.time()
f()
end = time.time()
print('spend %s' % (end - start))
foo()
show_time(foo)
foo=show_time(foo)
foo()
- 其可以被赋给其他变量:
在这里插入代码片def foo():
print('foo')
bar=foo
bar()
foo()
print(id(foo),id(bar)) #4321123592 432112392
2.其可以被定义在另外一个函数内(作为参数&作为返回值),类似于整形,字符串等对象。
在这里插入代码片#**********函数名作为参数************
def foo(func):
print('foo')
func()
def bar():
print('bar')
foo('bar')
# **********函数名作为返回值*********
def foo():
print('foo')
return bar
def bar():
print('bar')
b=foo()
b()
标题函数的嵌套以及闭包:
抛一个小问题:
在这里插入代码片def foo():
print('foo')
def bar():
print('bar')
# bar()
bar()
bar就是一个变量名,有自己的作用域的。
prthon允许创建嵌套函数。通过在函数内部der的关键字在声明一个函数即为嵌套:
在这里插入代码片# 想执行inner函数,两种方法
def outer():
x = 1
def inner():
print (x) # 1
# inner() # 2
return inner
# outer()
in_func=outer()
in_func()
定义:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的
变量进行引用,那么内部函数就被认为是闭包(closure).
标题装饰器概念:
装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下
增加额外的功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、
缓存、权限校验等应用场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量于函数功能本事无关的雷同代码
并继续重用。概括的讲,器的作用就是为已经存在的对象添加额外的功能。
业务生产中大量调用的函数:
在这里插入代码片def foo():
print('hell foo')
foo()
现在有一个新的需求,希望可以记录下函数执行时间,于是在代码中添加日志代码:
在这里插入代码片import time
def foo():
start_time=time.time()
print('hello foo')
time.sleep(3)
end_time=time.time()
print('spend %s'%(end_time-start-time))
foo()
bar()、bar2()也有类似的需求,怎么做?在bar函数里调用时间函数?这样就造成大量雷同的代码,
为了减少重复写代码,我们可以这样做,重定义一个函数,专门设定时间:
在这里插入代码片import time
def show_time(func):
start_time=time.time()
fun()
end_time=time.time()
print('spend %s'%(end_time-start_time))
def foo():
print('hello foo')
time.slepp(3)
show_time(foo)
标题简单装饰器:
if foo()==show_time(foo) :问题解决!
所以,我们需要show_time(foo)返回一个函数对象,
而这个函数对象内则是核心业务函数:执行func()与装饰函数时间计算,修改如下:
在这里插入代码片import time
def show_time(func):
def wrapper():
start_time=time.time()
func()
end_time=time.time()
print('spend %s'%(end_time-start_time))
return wrapper
def foo():
print('hello foo')
time.sleep(3)
foo=show_time(foo)
foo()
函数show_time就是装饰器,它把真正的业务方法func包裹在函数里面,看起来像foo被上下时间函数装饰了。
在这个例子中,函数进入和退出时,被称为一个横切面(Aspect),这种编程方式被称为面向切面的编程(Aspect-Oriented Peogramming).
@符号是装饰器的语法糖,在定义函数的时候使用,避免再一次赋值操作:
在这里插入代码片import time
def show_time(func):
def wrapper():
start_time=time.time()
func()
end_time=time.time()
print('spend %s'%(end_time-start_time))
return wrapper
@show_time # foo=show_time(foo)
def foo():
print('hello foo')
time.sleep(3)
@show_time # bar=show_time(bar)
def bar():
print('in the bar')
time.sleep(2)
foo()
print('**********')
bar()
如上所示,这样我们就可以省去bar = show_time(bar)这一句了,直接调用bar()即可得到想要的结果。如果我们有其他的类似函数,
我们可以继续调用装饰器来修饰函数,而不用重复修改函数或者增加新的封装。这样,我们就提高了程序的可重复利用性,并增加了程序的可读性。
这里需要注意的问题: foo=show_time(foo)其实是把wrapper引用的对象引用给了foo,而wrapper里的变量func之所以可以用,就是因为wrapper是一个闭包函数。
key:
@show_time帮我们做的事情就是当我们执行业务逻辑foo()时,执行的代码由粉框部分转到蓝框部分,仅此而已!
装饰器在Python使用如此方便都要归因于Python的函数能像普通的对象一样能作为参数传递给其他函数,可以被赋值给其他变量,可以作为返回值,可以被定义在另外一个函数内。