对缺省参数的理解
缺省参数和关键字参数对应:缺省参数是形参,关键字参数是实参。
调用函数的时候,如果没有传入该缺省参数的值,就取缺省参数的默认值,直白地说,就是你传,就用你的;你不传,我就用默认的。
def info(name,age=18):
# age = 18 就是缺省参数
print("name is %s" %name)
print("age is %d" %age)
# 调用函数
info(name='jack') # 未给age传参数,就去默认值age=18
# 输出结果:name is jack age is 18
# 调用函数
info(name='jack',age=66) # 传给关键字参数 则age=66
# 输出结果:name is jack age is 66
装饰器的理解
作用:写代码需要遵循开放封闭原则,它规定已经实现的功能代码不允许被修改,但是可以被扩展。
当我们需要为一段已经写好的代码添加功能的时候,在不改变源代码的情况下,加一个装饰器完成功能的添加功能。
例如:
(1)引入日志
(2)函数执行时间统计
(3)执行函数之前的预备处理
(4)执行函数之后的清理功能
(5)权限校验等场景
(6)缓存
装饰器实现原理
1、先了解闭包
# 定义一个函数
def test(number):
# 在函数内部再定义一个函数,并且这个函数用到了外边函数的变量
# 那么将这个函数以及用到的一些变量称之为闭包
def test_in(number_in):
print("in test_in函数,number_in is %d" %number_in)
return number + number_in
# 其实这里返回的就是闭包的结果
return test_in
demo = test(3)
print(demo(2))
@函数名(python的语法糖)@test下面的函数作为test函数的参数
def test1(func): def wrapped1(): # 验证1 return func() + '<xiexie>' # 这里不带()返回的是闭包的结果 return wrapped1 def test2(func): def wrapped2(): # 验证2 return func() + '<nihao>' # 这里不带(),返回的是闭包的结果 return wrapped2 @test1 @test2 def info(): return 'hello' print(info()) # 返回结果 # hello<nihao><xiexie>
装饰器原理分析
装饰阶段:将装饰器装饰的函数当做参数,传给装饰器,返回一个闭包(这里用到了闭包,外部的参数会传递给内部函数的引用,而不会被释放),并且赋值给原函数名,使原函数名指向了这个闭包。而此时装饰器的参数func指向原来的函数;
执行阶段: 调用原函数实际是调用的闭包,闭包在指向原函数前可以执行一段我们要加的逻辑。
装饰器开始装饰不是随着执行函数时装饰,而是在创建在对这个函数装饰时就装饰。
每装饰一个就创建一个闭包。
装饰问题,变量名指向问题
@test2
def info():
此时原函数名info指向@test2装饰创建的闭包---wrapped2
test2(func)的参数func,指向原来的函数info。
@test1
...
此时原函数名info指向@test1装饰创建的闭包---wrapped1;
test1(func)的参数func,指向@test2装饰
test2(func)的参数func,指向原来的函数info
装饰器参数(也可以是不定长参数)
from time import ctime,sleep
# 这个装饰器的作用是在函数开始之前打印开始时间
def timefun(func):
def wrapped_func(a,b):
print("%s called at %s" %(func.__name__,ctime()))
print(a,b)
func(a,b)
return wrapped_func
@timefun
def foo(a,b):
print(a+b)
foo(3,5)
sleep(2)
foo(2,4)
# 运行结果
# foo called at Tue Apr 10 15:50:30 2018
# 3 5
# 8
# foo called at Tue Apr 10 15:50:32 2018
# 2 4
# 6
类装饰器(扩展)
类装饰器其实是一个接口约束,它必须接受一个callable对象作为参数,然后返回一个callable对象。在Python中一般callable对象都是函数,但是也有例外。只要某个对象重写了call () 方法,那么对象就是callable的。
# 类装饰器demo
class Test(object):
def __init__(self,func):
print("---初始化---")
print("func name is %s" %func.__name__)
self.__func = func
def __call__(self):
print("---装饰器的功能---")
self.__func()
# 说明:
# 1. 当使用Test来装作装饰器对test函数进行装饰的时候,首先会创建Test的实例对象
# 并且会把test这个函数名当作参数传递到__init__方法中
# 即在__init__ 方法中的属性__func指向了test指向的函数
#
# 2. test指向了用Test创建出来的实例对象
#
# 3. 当在使用test()进行调用时,就相当于让这个对象(),因此会调用这个对象的__call__方法
# 4. 为了能够在__call__方法中调用原来test指向的函数体,所以在__init__方法中就需要
# 一个实例属性来保存这个函数体的引用
# 所以才有了self.__func = func 这句代码,从而在调用__call__方法中能够调用到
# test之前的函数体
@Test
def test():
print("---test---")
test()
showpy()