python基础:函数对象函数嵌套名称空间与作用域装饰器
Posted zhangshuyuan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python基础:函数对象函数嵌套名称空间与作用域装饰器相关的知识,希望对你有一定的参考价值。
-
函数对象
-
函数嵌套
-
名称空间与作用域
-
闭包函数
-
装饰器
-
练习
一 函数对象
#1 可以被引用 def max(x, y): return x if x > y else y func = max print(func(1, 2)) #2 可以当作参数传递 def max(x, y): return x if x > y else y def max_1(x, func): return func(x, 1) print(max_1(2, max)) #3 返回值可以是函数 #4 可以当作容器类型的元素 def foo(): print(‘foo‘) def bar(): print(‘bar‘) dic={ ‘foo‘:foo, ‘bar‘:bar, } while True: choice=input(‘>>: ‘).strip() if choice in dic: dic[choice]()
二 函数嵌套
def foo(): def bar(): print(‘from bar‘) bar() foo()
bar() #报错
三 名称空间与作用域
#名称空间:存放名字的地方,(x=1,1存放于内存中,名称空间正是存放名字x与1绑定关系的地方) #三种名称空间:局部名称空间--->全局名称空间--->内置名称空间
内置名称空间在 Python 解释器启动时就创建了,直到 Python 解释器退出时内置名称空间才失效。这使得我们可以在程序的任何位置使用内置名称空间内的名称,例如,id()
,print()
等函数。
全局命名空间,每个模块加载执行时创建的,记录了模块中定义的变量,包括模块中定义的函数、类、其他导入的模块、模块级的变量与常量。
python自带的内建命名空间,任何模块均可以访问,放着内置的函数和异常。
#1、作用域即范围 - 全局范围(内置名称空间与全局名称空间属于该范围):全局存活,全局有效 - 局部范围(局部名称空间属于该范围):临时存活,局部有效 #2、作用域关系是在函数定义阶段就已经固定的,与函数的调用位置无关,如下 x=1 def f1(): def f2(): print(x) return f2 x=100 def f3(func): x=2 func() x=10000 f3(f1()) #3、查看作用域:globals(),locals() LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__ locals 是函数内的名字空间,包括局部变量和形参 enclosing 外部嵌套函数的名字空间(闭包中常见) globals 全局变量,函数定义所在模块的名字空间 builtins 内置模块的名字空间
四 闭包函数
它是怎么产生的及用来解决什么问题呢。给出字面的定义先:闭包是由函数及其相关的引用环境组合而成的实体(即:闭包=函数+引用环境)
def counter(): n = 0 def incr(): nonlocal n x = n n += 1 return x return incr c = counter() print(c()) print(c()) print(c.__closure__[0].cell_contents) # 查看闭包的元素
用途:延迟计算
from urllib.request import urlopen def index(url): def get(): return urlopen(url).read() return get baidu = index(‘http://www.baidu.com‘) print(baidu().decode(‘utf-8‘))
五 装饰器
装饰器就是闭包函数的一种应用场景,用于拓展原来函数功能的一种函数
强调装饰器的原则:1 不修改被装饰对象的源代码 2 不修改被装饰对象的调用方式
装饰器的目标:在遵循1和2的前提下,为被装饰对象添加上新功能
装饰器函数以目标函数名为参数,且必须返回一个函数调用目标函数参数执行
import time def deco1(func): def wrapper(*args, **kwargs): start_time = time.time() print(‘deco1 start‘) func(*args, **kwargs) print(‘deco1 end‘) end_time = time.time() print(end_time - start_time) return wrapper def deco2(func): def wrapper(*args, **kwargs): start_time = time.time() print(‘deco2 start‘) func(*args, **kwargs) print(‘deco2 end‘) end_time = time.time() print(end_time - start_time) return wrapper @deco1 @deco2 def fun(x, y): time.sleep(2) print(x + y) fun(1, 2)
装饰器函数的参数为被装饰函数。装饰后执行被装饰函数相当于执行装饰器函数返回的函数,即例子中的wrapper
六 练习
# 编写函数,函数执行的时间是随机的 import random import time def func1(): t = random.random() print(‘sleeping time =‘, t) print(‘sleeping starts‘) time.sleep(t) print(‘sleeping ends‘) func1()
# 编写装饰器,为函数加上统计时间的功能 import random import time def deco(func): def wrapper(*args, **kwargs): stime = time.time() func(*args, **kwargs) etime = time.time() print(‘deco time:‘, (etime - stime)) return wrapper @deco def func(): t = random.random() print(‘sleeping time =‘, t) print(‘sleeping starts‘) time.sleep(t) print(‘sleeping ends‘) func()
# 编写装饰器,为多个函数加上认证功能,要求登录成功一次,在超时时间内无需重复登录,超过了超时时间,则必须重新登录 # db.txt内容:{‘user‘: ‘zsy‘, ‘passwd‘: ‘123‘} db = ‘db.txt‘ def auth(authtype=‘file‘): user_status = {‘user‘: None, ‘passwd‘: None} def origin_auth(func): def wrapper(*args, **kwargs): if authtype == ‘file‘: if user_status[‘user‘] != None or user_status[‘passwd‘] != None: func(*args, **kwargs) else: dict = eval(open(db, ‘r‘, encoding=‘utf-8‘).read()) user_name = input(‘Name: ‘) user_passwd = input(‘Passwd: ‘) if user_name == dict[‘user‘] and user_passwd == dict[‘passwd‘]: user_status[‘user‘] = user_name user_status[‘passwd‘] = user_passwd print(‘登录成功‘) func(*args, **kwargs) else: print(‘用户名或密码错误‘) elif authtype == ‘sql‘: print(‘暂无sql库‘) else: print(‘错误的authtyoe‘) return wrapper return origin_auth origin_auth = auth() @origin_auth def func(): print(‘func‘) func() @origin_auth def func2(): print(‘func2‘) func2()
# 编写装饰器,实现缓存网页内容的功能: 具体:实现下载的页面存放于文件中,如果文件内有值(文件大小不为0),就优先从文件中读取网页内容,否则,就去下载,然后存到文件中 import os, requests, hashlib engine_conf = { ‘file‘: {‘dirname‘: ‘db‘}, ‘sql‘: { ‘host‘: ‘127.0.0.1‘, ‘port‘: 3306, ‘user‘: ‘root‘, ‘password‘: ‘123‘}, ‘redis‘: { ‘host‘: ‘127.0.0.1‘, ‘port‘: 6379, ‘user‘: ‘root‘, ‘password‘: ‘123‘} } db = ‘db.txt‘ def make_cache(engine = ‘file‘): if engine not in engine_conf: raise TypeError(engine + ‘ not in engine_conf‘) user_status = {‘user‘: None, ‘passwd‘: None} def deco(func): if user_status[‘user‘] == None or user_status[‘passwd‘] == None: user_info = eval(open(db, ‘r‘).read()) user_name = input(‘User: ‘) user_passwd = input(‘Passwd: ‘) if user_name != user_info[‘user‘] or hashlib.md5(user_passwd.encode(‘utf-8‘)).hexdigest() != user_info[‘passwd‘]: print(‘用户名或密码错误‘) exit() else: user_status[‘user‘] = user_name user_status[‘passwd‘] = user_passwd def wrapper(url): if engine == ‘file‘: filename = hashlib.md5(url.encode(‘utf-8‘)).hexdigest() filepath = os.path.join(engine_conf[‘file‘][‘dirname‘], filename) if os.path.exists(filepath): print(‘已爬取该网页‘) else: content = func(url) if content == None: print(‘爬取内容为空‘) else: with open(filepath, ‘w‘, encoding=‘utf-8‘) as f: f.write(content) elif engine == ‘sql‘: pass elif engine == ‘redis‘: pass return wrapper return deco @make_cache() def get_html_text(url, *args, **kwargs): try: response = requests.get(url) response.encoding = response.apparent_encoding response.raise_for_status() return response.text except: return None get_html_text(‘http://www.baidu.com‘)
以上是关于python基础:函数对象函数嵌套名称空间与作用域装饰器的主要内容,如果未能解决你的问题,请参考以下文章
python--函数的返回值函数参数的使用名称空间与作用域函数嵌套函数对象