标签:源代码 语法 就是 *args min 状态 turn func font
函数对象:
函数是第一类对象
第一类对象:
指可以在执行期创造并作为参数传递给其他函数或存入一个变量的实体
第一类对象所特有的特性为:
函数、类、模块等所有对象都是第一类的
闭包函数:
函数内定义的函数为内部函数
内部函数包含对外部作用域而非全局作用域的引用
定义闭包函数的基本形式:
def 外部函数名(): 内部函数需要的变量 def 内部函数(): 引用外部变量 return 内部函数
举个栗子
def f1(): x=1 def f2(): print(x) return f2 f = f1() print(f) # <function f1.<locals>.f2 at 0x00000189C2226158> f() print(f.c.__closure__[0].cell_contents) 查看闭包元素 闭包函数都有 __closure__ 方法 这里内部函数f2打印x,f2中没有变量x,去上一层找,找到f1中的x,然后打印 这里的 f 就是闭包函数,包含了对f1中x的引用
特点:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使该函数无论在何处调用,优先使用自己外层包裹的作用域,永远携带着一种状态
拿到函数的内存地址,什么时候用就什么时候执行,惰性计算
闭包函数和作用域:
money = 666 def foo(name): print(‘%s have %s money‘ %(name,money)) def foo1(): money = 999 foo(‘shuai‘) foo1() # shuai have 666 money 这里打印不会是999,函数在定义时就已经确定了作用域,所以当doo函数内没有money时,会去找全局的money
闭包函数,让我一直有着一笔钱
money = 888 def func1(): name = ‘shuai‘ def func(): money = 666 def foo(): print(‘%s have %s money‘ %(name,money)) return foo return func f = func1() f1 = f() def foo1(): money = 999 f1() foo1() 包了两层 先看func1和func,这两个函数返回闭包函数 func,包含了 name func 和 foo ,这俩函数返回闭包函数 foo,包含了 money f = func1() 拿到 func,再执行f1 = f() 拿到 foo
简单应用:
from urllib.request import urlopen def get(url): return urlopen(url).read() print(get(‘http://www.xiaohua100.cn‘)) 获取校花网信息 问题:每次都要传url,网站过多,url是没法记住的 闭包应用 from urllib.request import urlopen def index(url): def get(): return urlopen(url).read() return get xiaohua = index(‘http://xiaohua100.cn‘) print(xiaohua()) jidong = index(‘https://www.jd.com/‘) print((jidong())) 这样想要下载哪个就执行哪个,不用就放着,并且不用传url;
装饰器
实际就是闭包函数的
软件开发的开发封闭原则
对扩展是开放的,对修改是封闭的
装饰器本身可以是任意可调用对象,被装饰者也可以是任意可调用对象 装饰器的原则:1 不修改被装饰对象的源代码 2 不修改被装饰对象的调用方式 装饰器的目标:在遵循装饰器原则前提下,为被装饰对象添加上新功能
通过装饰器来检测程序运行时间:
import time import random # 装饰器 def func(func): # func = index def timmer(): start_time = time.time() func() # index() end_time = time.time() print(‘运行时间:%s‘ %(end_time-start_time)) return timmer #被装饰对象 def index(): time.sleep(random.randrange(1,6)) print(‘欢迎!‘) index = func(index) index()
上面的问题:
如果还有其他的被装饰对象,那么装饰谁就得写一遍代码: index = func(index) index() admin_page = func(admin_page ) admin_page () 这样很麻烦
@语法:
写在在被装饰对象的正上方 :@装饰器
流程跟上方是一样的:将下方函数当做参数传给装饰器,把返回的结果重新赋值给下方函数的名字
上面的代码可以这样写,省去了 index = func(index) @func # func(index) def index(): time.sleep(random.randrange(1,6)) print(‘欢迎!‘) index()
举个栗子
import time import random def timmer(func): def f_time(): start_time = time.time() func() end_time = time.time() print(‘运行时间 %s‘ %(end_time-start_time)) return f_time def func(func): def foo(): name = input(‘用户名:‘) pwd = input(‘密码:‘) if name == ‘shuai‘ and pwd == ‘123‘: print(‘登录成功!‘) func() else: print(‘登录失败!‘) return foo @func @timmer # 在下面的先执行,这样就把认证也计算在内 def index(): # time.sleep(random.randrange(1,6)) time.sleep(2) print(‘欢迎!‘) index()
注:
被装饰的对象,上面的装饰器,离得近的先执行
分析:
@timmer 是 index = timmer(index) 这里传入的是最原始的index,得到包含了f_time的
@func 是 index = auth(timmer(index)) 这里传入的index是@timmer执行后的index,然后再赋值给index
有参装饰器:
db_path=r‘F:\python基础\a.txt‘ login_dic={ ‘user‘:None, ‘status‘:False, } def deco(auth_type=‘170‘): def auth(func): def wrapper(*args,**kwargs): if auth_type == ‘170‘: if login_dic[‘user‘] and login_dic[‘status‘]: res = func(*args, **kwargs) return res name=input(‘用户名: ‘) password=input(‘密码: ‘) with open(db_path,‘r‘,encoding=‘utf-8‘) as f: user_dic=eval(f.read()) if name in user_dic and password == user_dic[name]: print(‘登录成功‘) login_dic[‘user‘]=name login_dic[‘status‘]=True res=func(*args,**kwargs) return res else: print(‘登录失败‘) elif auth_type == ‘160‘: print(‘长的矮的‘) elif auth_type == ‘180‘: print(‘长的高的‘) else: print(‘没有的选项‘) return wrapper return auth @deco(auth_type=‘170‘) #@auth #index=auth(index) 这里先执行deco函数,执行的结果auth作为index的装饰器 def index(): print(‘欢迎登录‘) @deco(auth_type=‘160‘) def home(name): print(‘欢迎%s登录‘ %name) index() home(‘shuai‘) 这里是简单例子,根据身高来执行不同的操作,这个身高是一个条件,使用闭包把这个变量包进去,在使用装饰器deco时,需要传入这个值,这时deco执行,返回autn,所以装饰器就变成了@auth,然后就像无参装饰器一样运行了
练练
(1)
tag = True while tag: name = input(‘用户名:‘) pwd = input(‘密码:‘) f = open(‘a.txt‘,encoding=‘UTF-8‘) for line in f: s = eval(line) # print(type(s)) if name == s[‘name‘] and pwd == s[‘password‘]: print(‘登录成功!‘) tag = False break print(‘登录失败!‘)
(2)
from urllib.request import urlopen import os cache_path=r‘F:\下载\cache.txt‘ def make_cache(func): def wrapper(*args,**kwargs): if os.path.getsize(cache_path): #有缓存 print(‘\033[45m=========>有缓存\033[0m‘) with open(cache_path,‘rb‘) as f: res=f.read() else: res=func(*args,**kwargs) #下载 with open(cache_path,‘wb‘) as f: #制作缓存 f.write(res) return res return wrapper @make_cache def get(url): return urlopen(url).read() get(‘https://www.baidu.com/‘)
标签:源代码 语法 就是 *args min 状态 turn func font
原文地址:http://www.cnblogs.com/Mr-chenshuai/p/7901178.html