Python之装饰器、迭代器和生成器

一、基础准备

1.函数嵌套

  • 函数嵌套定义
  • 函数嵌套调用
  • 1 #函数的嵌套定义:在一个函数的内部,又定义另外一个函数
    2 def f1():
    3     print('f1')
    4     def f2():
    5         print('f2')
    6     f2()
    7 f1()
    8 f2() #会报错,why?->名称空间和作用域有关
    View Code

     

2.名称空间和作用域

什么是名称空间?

存放名字与变量值绑定关系的地方

名称空间的分类

内置名称空间:在python解释器启动时产生,存放一些python内置的名字

1 max=1
2 print(globals())
3 print(globals()['__builtins__'])
4 print(dir(globals()['__builtins__'])). #dir查看模块的方法
5 '''{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x1005da4a8>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': '/Users/yanlingzhao/Desktop/python/day4/day4/test.py', '__cached__': None, 'max': 1}
6 <module 'builtins' (built-in)>
7 ['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'ModuleNotFoundError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'RecursionError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '__build_class__', '__debug__', '__doc__', '__import__', '__loader__', '__name__', '__package__', '__spec__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
8 '''
View Code

 

全局名称空间:在执行文件时产生,存放文件级别定义的名字(除了内置名称空间和函数内定义的变量之外的变量)

 1 x=1
 2 def func():
 3     y=2
 4     def f1():pass
 5     print
 6 class Foo:
 7     def f(self):
 8         print('test f')
 9 if x==1:z=3
10 print(globals())   #查看全局名称空间中的存储内容
11 '''{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000000000215A470>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/study/code/day4/day4/test.py', '__cached__': None, 'x': 1, 'func': <function func at 0x0000000001D53E18>, 'Foo': <class '__main__.Foo'>, 'z': 3}
12 '''
View Code

 

局部名称空间

#局部名称空间:在执行文件的过程中,如果调用了函数,则会产生该函数的局部名称空间
#用来存放该函数内定义的名字,该名字在函数调用时生效,在函数调用结束后失效
 1 x=1
 2 def func():
 3     y=2
 4     def f1():pass
 5     print(locals())  #查看局部名称空间内容
 6 func()
 7 '''{'f1': <function func.<locals>.f1 at 0x00000000026DD9D8>, 'y': 2}
 8 '''
 9 
10 class Foo:
11     def f(self):
12         print(locals())
13 '''没有调用函数f,所有不会打印局部名称空间内容'''
View Code

名称空间的加载和查找顺序

#加载顺序:内置---》全局---》局部
#优先掌握一:名字的查找顺序是:局部-》全局-》内置

作用域 

#作用域:作用的范围,
#全局作用域:全局存活,全局有效:globals()
#局部作用域:临时存活,局部有效:locals()
1 max=1    #全局作用域,函数内部和文件级别都可以访问
2 def foo():
3     max=2  #局部作用域,只能在函数内部访问
4     print(max)
5 foo()
6 print(max)
7 '''2
8 1'''   #先找全局max=1的名称空间
9 '''<built-in function max>'''  #注释掉max=1时找到内置变量
View Code
 1 x=11111111111111111111111111111111111111111111
 2 def f1():
 3     x=1
 4     y=2
 5     def f2():pass
 6     print(locals())  #局部
 7     print(globals())  #全局
 8 
 9 f1()
10 print(locals() is globals())  #在文件级别全局就等于局部,从本层开始寻找命名空间
11 print(dir(globals()['__builtins__']))
View Code

改变作用域规则的两个关键词global和nonlocal

 1 #改变作用域规则的两个关键词:global nonlocal
 2 x=1
 3 def f1():
 4     global x  #使用全局变量
 5     x=2
 6     print(globals())
 7     print(locals())
 8 f1()
 9 print(x)
10 '''{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x1007da4a8>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': '/Users/yanlingzhao/Desktop/python/day4/day4/test.py', '__cached__': None, 'x': 2, 'f1': <function f1 at 0x100762e18>}
11 {}
12 2
13 '''
14 
15 
16 
17 l=[]
18 def f2():
19     l.append('f2')   #列表是可变类型,所以可以在局部改变全局的值
20 
21 f2()
22 print(l)
23 
24 
25 #nonlocal可以改变上一层的局部变量
26 x=0
27 def f1():
28     x=1
29     def f2():
30         x=2
31         def f3():
32             nonlocal x
33             x=3
34             print('f3:%s'%x)
35         f3()
36         print('f2:%s'%x)
37     f2()
38     print('f3:%s'%x)
39 f1()
40 '''f3:3
41 f2:3
42 f3:1'''
View Code

 

函数调用时,必须去函数定义的位置去找作用域关系(作用域关系,在函数定义时已经固定了,与函数调用位置无关)

 1 x=1
 2 def  f1():
 3     def f2():
 4         print(x)
 5     return f2
 6 
 7 func=f1()
 8 x=10000000
 9 
10 def foo(func):
11     x=300000000
12     func() #f2()
13 foo(func)
14 x=10000000000000000000000
View Code

 3.闭包函数

函数对象-》打破函数层级调用关系(函数可以作为参数使用)
作用域->在函数定义时,已经决定了作用域跟调用无关
------》》
闭包函数:1.定义在函数内部的函数
               2.包含对外部作用域名字的引用
               3.而不是对全局作用域名字的引用
               则该内部函数被称作闭包函数

 

 1 #闭包函数的应用
 2 import requests
 3 def index(url):
 4     #url = 'www.baidu.com'
 5     x=1
 6     def wrapper():
 7         print(x)
 8         return requests.get(url).text
 9     return wrapper
10 baidu_web=index('http://www.baidu.com')  #包裹了百度url的wrapper闭包函数
11 netease_web=index('http://www.163.com')   #包裹了网易url的wrapper闭包函数
12 print(baidu_web())   #执行闭包函数
13 print(netease_web())
14 
15 print(baidu_web.__closure__[0].cell_contents)   #输出结果'''http://www.baidu.com'''
16 print(baidu_web.__closure__[1].cell_contents)   #输出结果'''1'''
View Code

二、装饰器

1.开放封闭原则:对扩展是开放的,对修改是封闭的
2.什么是装饰器:装饰它人的工具;装饰器本身可以是任意可调用对象,被装饰的对象本身也可以是任意可调用对象
3.装饰器遵循的原则:1)不修改被装饰对象的源代码 2)不修改被装饰对象的调用方式
4.装饰器的目的:在遵循装饰器原则的前提下,为其增加新功能
5.装饰器使用规则:@装饰器名,必须写在装饰器对象的正上方,并且单独一行
代码演示:
 1 #!_*_coding=utf-8_*_
 2 import time
 3 
 4 def timmer(fuc):
 5     def wrapper(*args,**kwargs):
 6         start=time.time()
 7         time.sleep(0.3)
 8         res=fuc(*args,**kwargs)
 9         end=time.time()
10         print('total time:%s'%(end-start))
11         return res
12     return wrapper
13 
14 @timmer  #index=timmer(index)
15 def index():
16     print('wellcome to index')
17     x=1
18     return x
19 @timmer   #home=timmer(home)
20 def home(name):
21     print('wellcome to home:%s'%name)
22 
23 print(index())
24 print(home('zyl'))
25 '''
26 wellcome to index
27 total time:0.303838014603
28 1
29 wellcome to home:zyl
30 total time:0.300426006317
31 None'''
View Code

6.装饰器分类:无参装饰器和有参装饰器

无参装饰器实例:

账户认证装饰器

 1 #!_*_coding=utf-8_*_
 2 
 3 '''
 4 {'zyl':'123'}
 5 '''
 6 current_user={'user':None}
 7 def auth(fuc):
 8     def wrapper(*args,**kwargs):
 9         if current_user['user']:
10             return  fuc(*args,**kwargs)
11         name = input('name: ').strip()
12         password = input('password: ').strip()
13         with open('db.txt', 'r', encoding='utf-8') as f:
14             user_dic = eval(f.read())
15         if name in user_dic and password == user_dic[name]:
16             res = fuc(*args, **kwargs)
17             current_user['user'] = name
18         else:
19             print('name and pw error')
20 
21 
22 
23         return res
24     return wrapper
25 
26 @auth
27 def index():
28     print('wellcome to my index')
29 
30 @auth
31 def home(account):
32     print('to the account:%s'% account)
33 
34 index()
35 home('text')
View Code

有参装饰器:

 1 #!_*_coding=utf-8_*_
 2 
 3 '''
 4 {'zyl':'123'}
 5 '''
 6 current_user={'user':None}
 7 def auth(auth_type='file'):
 8     def deco(fuc):
 9         def wrapper(*args, **kwargs):
10             if auth_type == 'file':
11                 if current_user['user']:
12                     return fuc(*args, **kwargs)
13                 name = input('name: ').strip()
14                 password = input('password: ').strip()
15                 with open('db.txt', 'r', encoding='utf-8') as f:
16                     user_dic = eval(f.read())
17                 if name in user_dic and password == user_dic[name]:
18                     res = fuc(*args, **kwargs)
19                     current_user['user'] = name
20                     return res
21                 else:
22                     print('name and pw error')
23 
24             elif auth_type == 'mysql':
25                 print('mysql')
26             else:
27                 print('not valid auth_type ')
28         return wrapper
29     return deco
30 
31 @auth('mysql')  #@deco
32 def index():
33     print('wellcome to my index')
34 
35 @auth()
36 def home(account):
37     print('to the account:%s'% account)
38 
39 index()
40 home('text')
41 '''mysql
42 name: zyl
43 password: 123
44 to the account:text
45 '''

继承函数注释内容

from functools import wraps

@wraps(fuc)放到最里面函数定义的上面

 1 #补充一:wraps
 2 
 3 import time
 4 from functools import wraps
 5 
 6 def timmer(func):
 7     @wraps(func)
 8     def wrapper(*args,**kwargs):
 9         start=time.time()
10         res=func(*args,**kwargs)
11         stop=time.time()
12         print('run time is %s' %(stop-start))
13         return res
14     return wrapper
15 
16 
17 @timmer # index=timmer(index)
18 def index():
19     '''这是index函数'''
20     time.sleep(3)
21     print('welcome to index')
22     return 123
23 
24 print(index.__doc__)
25 print(help(index))
View Code

多层个继承

 1 #补充二:一个函数头顶上可以多个装饰器
 2 import time
 3 from functools import wraps
 4 current_user={'user':None}
 5 
 6 def timmer(func):
 7     @wraps(func)
 8     def wrapper(*args,**kwargs):
 9         start=time.time()
10         res=func(*args,**kwargs)
11         stop=time.time()
12         print('run time is %s' %(stop-start))
13         return res
14     return wrapper
15 def auth(auth_type='file'):
16     def deco(func):
17         def wrapper(*args, **kwargs):
18             if auth_type == 'file':
19                 if current_user['user']:
20                     return func(*args, **kwargs)
21                 name = input('name: ').strip()
22                 password = input('password: ').strip()
23 
24                 with open('db.txt', encoding='utf-8') as f:
25                     user_dic = eval(f.read())
26                 if name in user_dic and password == user_dic[name]:
27                     res = func(*args, **kwargs)
28                     current_user['user'] = name
29                     return res
30                 else:
31                     print('user or password error')
32             elif auth_type == 'mysql':
33                 print('mysql')
34 
35             elif auth_type == 'ldap':
36                 print('ldap')
37             else:
38                 print('not valid auth_type')
39         return wrapper
40     return deco
41 
42 
43 
44 @timmer #index=timmer(wrapper)
45 @auth() # @deco #index=deco(index) #wrapper
46 def index():
47     '''这是index函数'''
48     time.sleep(3)
49     print('welcome to index')
50     return 123
51 
52 # print(index.__doc__)
53 # print(help(index))
54 
55 index()
View Code

 三、迭代器

  1 #迭代:是一个重复的过程,每一次重复,都是基于上一次的结果而来
  2 # while True: #单纯的重复
  3 #     print('你瞅啥')
  4 
  5 # l=['a','b','c','d']
  6 # count=0
  7 # while count < len(l):
  8 #     print(l[count])
  9 #     count+=1
 10 
 11 dic={'name':'egon','sex':'m',"age":18} #上述按照索引的取值方式,不适于没有索引的数据类型
 12 
 13 #迭代器:
 14 #可迭代对象iterable:凡是对象下有__iter__方法:对象.__iter__,该对象就是可迭代对象
 15 # s='hello'
 16 # l=['a','b','c','d']
 17 # t=('a','b','c','d')
 18 # dic={'name':'egon','sex':'m',"age":18}
 19 # set1={1,2,3}
 20 # f=open('db.txt')
 21 
 22 # s.__iter__()
 23 # l.__iter__()
 24 # t.__iter__()
 25 # dic.__iter__()
 26 # set1.__iter__()
 27 # f.__iter__()
 28 
 29 
 30 #迭代器对象:可迭代对象执行内置的__iter__方法,得到的结果就是迭代器对象
 31 
 32 # dic={'name':'egon','sex':'m',"age":18}
 33 #
 34 # i=dic.__iter__()
 35 # # print(i) #iterator迭代器
 36 #
 37 # # i.__next__() #next(i)
 38 # print(next(i))
 39 # print(next(i))
 40 # print(next(i))
 41 # print(next(i)) #StopIteration
 42 #
 43 # l=['a','b','c','d']
 44 #
 45 # i=l.__iter__()
 46 # print(next(i))
 47 # print(next(i))
 48 # print(next(i))
 49 # print(next(i))
 50 # print(next(i)) #StopIteration
 51 
 52 
 53 
 54 
 55 #不依赖于索引的取值方式
 56 # l=['a','b','c','d']
 57 # dic={'name':'egon','sex':'m',"age":18}
 58 # iter_l=iter(l)
 59 # iter_dic=iter(dic)
 60 # while True:
 61 #     try:
 62 #         # print(next(iter_l))
 63 #         k=next(iter_dic)
 64 #         print(k,dic[k])
 65 #     except StopIteration:
 66 #         break
 67 
 68 
 69 #什么是迭代器对象:
 70 #1 有__iter__,执行得到仍然是迭代本身
 71 #2 有__next__
 72 
 73 
 74 #迭代器对象的优点
 75 #1:提供了一种统一的(不依赖于索引的)迭代方式
 76 #2:迭代器本身,比起其他数据类型更省内存
 77 # l=['a','b','c','d']
 78 # i=iter(l)
 79 
 80 # dic={'a':1,'b':2}
 81 # x=dic.keys()
 82 # print(x)
 83 # i=x.__iter__()
 84 #
 85 # with open('a.txt') as f:
 86 #     # print(next(f))
 87 #     # print(next(f))
 88 #     # print(next(f))
 89 #     f.read()
 90 
 91 
 92 #迭代器对象的缺点
 93 #1:一次性,只能往后走,不能回退,不如索引取值灵活
 94 #2:无法预知什么时候取值结束,即无法预知长度
 95 # l=['a','b','c','d']
 96 # i=iter(l)
 97 # print(next(i))
 98 # print(next(i))
 99 # print(next(i))
100 
101 
102 #for循环原理
103 
104 #
105 # l=['a','b','c','d']
106 # for item in l: #iter_l=l.__iter__()
107 #     print(item)
108 
109 
110 # for item in {1,2,3,4}:
111 #     print(item)
112 
113 
114 # with open('a.txt') as f:
115 #     # for line in f: #i=f.__iter__()
116 #     #     print(line)
117 #     print(f is f.__iter__())
118 
119 
120 
121 
122 
123 #补充:判断可迭代对象与迭代器对象(了解)
124 
125 from collections import Iterable,Iterator
126 s='hello'
127 l=['a','b','c','d']
128 t=('a','b','c','d')
129 dic={'name':'egon','sex':'m',"age":18}
130 set1={1,2,3}
131 f=open('a.txt')
132 
133 
134 # print(isinstance(s,Iterable))
135 # print(isinstance(l,Iterable))
136 # print(isinstance(t,Iterable))
137 # print(isinstance(dic,Iterable))
138 # print(isinstance(set1,Iterable))
139 # print(isinstance(f,Iterable))
140 
141 print(isinstance(s,Iterator))
142 print(isinstance(l,Iterator))
143 print(isinstance(t,Iterator))
144 print(isinstance(dic,Iterator))
145 print(isinstance(set1,Iterator))
146 print(isinstance(f,Iterator))
View Code

 

posted @ 2017-07-26 09:44  ling_distance  阅读(203)  评论(0编辑  收藏  举报