一 函数的嵌套
def func(*args,**kwargs): def func_inner(a,b,c): print(a,b,c) func_inner(*args,**kwargs) func(1,2,c=3)
针对函数的嵌套,外层函数定义阶段,内层函数调用阶段,*args,**kwargs这样写以后,外层函数调用时,只需要和内层函数定义阶段相匹配就ok了。
二 三元表达式
pass
三名称空间(namespace)与作用域
名称空间:
名称空间的分类
名称空间的加载顺序
名称空间的生命周期
名称空间 谁可以使用谁
作用域
三种名称空间的作用域
作用范围
四 闭包
定义:
调用外层函数,返回内层函数的地址,这个内层函数是带着外层函数的环境变量返回的。
def foo(): name='egon' def bar(): print(name) return bar b=foo() name='alex' b()
输出:
egon foo就是闭包函数,不管在任何位置调用,都自带对外界作用域的引用。
函数名.__closure__
如果不是闭包函数,返回None
如果是闭包函数,返回作为闭包函数调用外层环境的变量地址。以元组的形式返回,每个元素都是一个地址。
五 关键字
locals() :返回当前作用域的局部变量。
Return a dictionary containing the current scope's local variables.
nonlocal :,对外层的变量有用,但不是全局变量。否则,报错。
a=100 def func1(): def func2(): nonlocal a print(a) func1()
报错信息:
SyntaxError: no binding for nonlocal 'a' found
global
六 函数的本质
一等公民
函数名
egon语录:函数的作用域关系跟定义位置有关,跟调用位置无关。
money=100 def foo(): print('money:',money) def bar(): money=1000 foo() bar()
输出:
money: 100 #foo()函数定义在全局。尽管是在bar函数局部名称空间内被调用,但money的作用域还是要去全局中找。
在上述例子的基础上的拓展
money=100 def foo(): print('money:',money) money=10 def bar(): money=1000 foo() bar()
输出:
money: 10 #money:10 ,这跟函数的从上到下的加载顺序有关,但引用的money是全局变量还是不变的。
七 带参数的装饰器
装饰器的外层右加了一层装饰器。
def wrapper(func): def bar(*args): print('======') res=func(*args) return res return bar @wrapper def plus(x,y): return x+y res=plus(2,2) print(res) #这是最基本的装饰器
带参数的装饰器。想要传参数,将参数写在现成的装饰器的外面,在装饰器的外面在套一层函数。最内层被装饰的函数可以调用到外层的所有参数,可以根据第二层的装饰器的参数,来决定第一层装饰器是否执行。
def auth(tag): def wrapper(func): def bar(*args): if tag: print('======') res=func(*args) return res return bar return wrapper @auth(0) def plus(x,y): return x+y @auth(1) def multi(x,y): return x*y res=plus(2,2) print(res) print('---------------------------------') res=multi(2,3) print(res)
egon讲的另一个例子。调用函数时自动将函数地址保存到一个字典中,key值是传的参数,value值是函数内存地址。
func_dict={} def auth(key): def deco(func): func_dict[key]=func return deco @auth('foo') #@auth('foo)=@wrapper foo=wrapper(foo) def foo(): print('foo') @auth('bar') def bar(): print('bar')
讲解时的思路是: 因为要传参,所以是 三层装饰器。先定义了auth(key),放一个参数进去。 deco(func),还是正常放函数。 func_dict[key]=func,走到这一步,要实现的功能已经实现了,没必要在写wrapper函数了。
思路非常清晰。
这样实现的效果是 auth传入的参数名随意改,对应的函数实际不会变,达到了隐藏函数的效果。最后直接 func_dict['foo']()就可以运行。
八 装饰器的一个应用 @wraps
Python装饰器(decorator)在实现的时候,被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变),为了不影响,Python的functools包中提供了一个叫wraps的decorator来消除这样的副作用。写一个decorator的时候,最好在实现之前加上functools的wrap,它能保留原有函数的名称和docstring。
from functools import wraps def wrapper(func): def inner(*args,**kwargs): return func(*args,**kwargs) return inner def foo(): ''' foo函数 :return: ''' x=1 return x print(foo.__name__,foo.__doc__) print('*'*50) @wrapper def foo(): ''' foo函数 :return: ''' x=1 return x print(foo.__name__,foo.__doc__) print('*'*50) def wrapper(func): @wraps(func) def inner(*args,**kwargs): return func(*args,**kwargs) return inner @wrapper def foo(): ''' foo函数 :return: ''' x=1 return x print(foo.__name__,foo.__doc__)
输出:
foo foo函数 :return: ************************************************** inner None ************************************************** foo foo函数 :return: