函数 - 命名空间/闭包/装饰器/生成器/迭代器

1.命名空间 == 名称空间 namespace
存放名字的地方

x=1 名称空间存放 x 和 x与1绑定关系 类似{x:id(1)}

1.1.
名称空间分三种:
  1.locals 是函数内的名称空间,包括局部变量和形参 locals()
  2.globals 打印程序脚本的所有变量 globals()
  3.builtins 内置模块的名字空间 python 一启动自带的那些自带函数 len() ord() dir(__builtins__)

1.2.
dir(__builtins__) #pythond的内置方法

['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', 'WindowsError', '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']

1.3.
名称空间 与 作用域 有很大的关系
不同变量的作用域不同就是由这个变量所在的命名空间决定的

作用域即范围scope
全局范围:全局存活 全局有效
局部范围:临时存活 局部有效
查看作用域范围 globals() locals()

1.4.
作用域的查找顺序:
LEGB
L: local 函数内的名称空间
E: enclosing 外部嵌套函数的名称空间
G: global 全局变量 函数定义所在模块的名称空间
B: builtins 内置模块的名称空间

--------------------------------------------------

2.闭包

 1   def func():
 2     n = 10
 3     def fun2():
 4         print('fun2:',n)
 5     return fun2
 6 
 7     res = func()
 8     print(res)
 9     res()
10 ----
11   <function func.<locals>.fun2 at 0x000001BB92CDFA60>
12   fun2: 10


闭包:函数内部的子函数返回,在外部调用子函数时,其实函数已经结束,但是在调用子函数时,函数内部的局部变量任然有效。

--------------------------------------------------

3.装饰器

参考:http://www.cnblogs.com/alex3714/articles/5765046.html
youporn.com

软件开发 的 一个原则:“开放-封闭”原则
    开放:对现有功能的扩展开放
    封闭:已实现的功能代码块不应该被修改
带参数的装饰器

  1 --------------
  2 # 语法糖 装饰器
  3 user_status = False
  4 def login(func): #henan
  5 
  6     def inner():
  7         _username = 'alice'
  8         _password = '123'
  9         global user_status
 10 
 11         if user_status == False:
 12             username = input('username:').strip()
 13             password = input('password:').strip()
 14             if username == _username and password == _password:
 15                 print('welcome login...')
 16                 user_status = True
 17             else:
 18                 print('Wrong username or password!')
 19         else:
 20             print("用户已经登录,验证通过...")
 21 
 22         if user_status == True:
 23             func()  # 验证通过就调用相应的功能
 24 
 25     return inner
 26 
 27 
 28 def home():
 29     print("---首页----")
 30 @login
 31 def america():
 32     print("----欧美专区----")
 33 def japan():
 34     print("----日韩专区----")
 35 @login # henan = login(henan)
 36 def henan():
 37     print("----河南专区----")
 38 
 39 home()
 40 henan()
 41 america()
 42 ----------------
 43 # 带参数的装饰器
 44 user_status = False
 45 def login(func): #henan
 46 
 47     def inner(arg):
 48         _username = 'alice'
 49         _password = '123'
 50         global user_status
 51 
 52         if user_status == False:
 53             username = input('username:').strip()
 54             password = input('password:').strip()
 55             if username == _username and password == _password:
 56                 print('welcome login...')
 57                 user_status = True
 58             else:
 59                 print('Wrong username or password!')
 60         else:
 61             print("用户已经登录,验证通过...")
 62 
 63         if user_status == True:
 64             func(arg)  # 验证通过就调用相应的功能
 65 
 66     return inner
 67 
 68 
 69 def home():
 70     print("---首页----")
 71 @login
 72 def america():
 73     print("----欧美专区----")
 74 def japan():
 75     print("----日韩专区----")
 76 @login # henan = login(henan)
 77 def henan(style):
 78     print("----河南专区----",style)
 79 
 80 home()
 81 henan('3p')
 82 -------------------
 83 # 装饰器 有的带参数 有的不带参数 非固定参数 支持多个参数
 84 user_status = False
 85 def login(func): #henan
 86 
 87     def inner(*args,**kwargs):
 88         _username = 'alice'
 89         _password = '123'
 90         global user_status
 91 
 92         if user_status == False:
 93             username = input('username:').strip()
 94             password = input('password:').strip()
 95             if username == _username and password == _password:
 96                 print('welcome login...')
 97                 user_status = True
 98             else:
 99                 print('Wrong username or password!')
100         else:
101             print("用户已经登录,验证通过...")
102 
103         if user_status == True:
104             func(*args,**kwargs)  # 验证通过就调用相应的功能
105 
106     return inner
107 
108 
109 def home():
110     print("---首页----")
111 @login
112 def america():
113     print("----欧美专区----")
114 @login
115 def japan(x,y='abc'):
116     print("----日韩专区----",x,y)
117 @login # henan = login(henan)
118 def henan(style):
119     print("----河南专区----",style)
120 
121 home()
122 henan('3p')
123 america()
124 japan(2,'asa')
125 --------------------
126 # 带参数的装饰器 又包一层
127 user_status = False
128 def login(auth_type): #henan
129     print('asa')
130     def outer(func): #henan
131         def inner(*args,**kwargs):
132             _username = 'alice'
133             _password = '123'
134             global user_status
135 
136             if user_status == False:
137                 username = input('username:').strip()
138                 password = input('password:').strip()
139                 if username == _username and password == _password:
140                     print('welcome login...')
141                     user_status = True
142                 else:
143                     print('Wrong username or password!')
144             else:
145                 print("用户已经登录,验证通过...")
146 
147             if user_status == True:
148                 func(*args,**kwargs)  # 验证通过就调用相应的功能
149 
150         return inner
151 
152     return outer
153 
154 
155 def home():
156     print("---首页----")
157 @login('wx')
158 def america():
159     print("----欧美专区----")
160 @login('wb')
161 def japan(x,y='abc'):
162     print("----日韩专区----",x,y)
163 @login ('qq') # henan =login('qq')(henan) = inner
164 def henan(style):
165     print("----河南专区----",style)
166 
167 home()
168 henan('3p')
169 america()

--------------------------------------------------

4.生成器

4.1.列表生成式:
作用:1.一个for循环一行搞定
           2.高大上
a=[i for i in range(10)] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
a= [ i if i <5 else i*i for i in range(10)] = [0, 1, 2, 3, 4, 25, 36, 49, 64, 81]

a2=(i for i in range(1000)) = <generator object <genexpr> at 0x0000026D1D0DF048> 生成器
next(a2) = 0
next(a2) = 1

4.2.生成器的特性:
只负责生产,只能往前走,不能回退,生产结束时,若在生产,就报错StopIteration
for i in a2:               while True:
  print(i)                     next(a2)
循环生成器结束时,for不会报错,while会报错

python2的xrange(100)=python3的range(100) 底层都是生成器 不浪费空间
python3:range(10)=range(0, 10)=生成器 底层就是生成器,存放生产的公式
python3:xrange() 没有
python2:range(10)=[0,1,2,3,4,5,6,7,8,9]=list
python2:xrange(10)=xrange(10)=生成器

4.3.用函数写生成器的复杂算法
斐波那契数列(Fibonacci)
1,1,2,3,5,8,13,21,34,... 除第一个和第二个外,任何一个数都由前两个数相加

斐波那契数列用列表生成式写不出来,就用函数写出来

 1 def fib(max):
 2     n,a,b=0,0,1
 3     while n<max:
 4         print(b)
 5         a,b=b,a+b
 6         n+=1
 7     return 'done'
 8   fib(15)
 9 1
10 1
11 2
12 3
13 5
14 8
15 13
16 21
17 34
18 55
19 89
20 144
21 233
22 377
23 610
24 'done'
25 -------
26 a,b=1,2
27 a,b=b,a+b 
28 相当于 t=a a=b  b=t+b 
29 -------
30 def fib(max):
31     n, a, b = 0, 0, 1
32     while n < max:
33         print('before yield')
34         yield b #变成了生成器  通过函数写了一个生成器 把函数的执行过程冻结在这一步,并且把b的值返回给外面的next()
35         print(b)
36         a, b = b, a+b
37         n += 1
38     return 'done'
39 
40 f=fib(15) #turn function into a generator
41 next(f) #first time call next
42 next(f)
43 ---
44 before yield
45 1 
46 before yield 


yield作用:变成了生成器 通过函数写了一个生成器 把函数的执行过程冻结在这一步,并且把b的值返回给外面的next()

4.4
生成器总结:

4.4.1.
a =(i for i in range(10)) = <generator object <genexpr> at 0x0000026D1D09DFC0>
next(a) = 0
next(a) = 1
... ...最后生产完之后会报错

4.4.2.
a = (i for i in range(10))
while True:
    print(next(a))
0
1
2
... ...最后生产完之后会报错

4.4.3.
a = (i for i in range(10))
for i in a:
    print(i)
0
1
2
... ...最后生产完之后不会报错

------------------------------------

5.生成器的创建方式
5.1 列表生成式 只能写到三元运算 a = (i for i in range(10))
5.2 函数 yield 使函数变成了生成器,冻结当前的执行过程,

 1  def range2(n):
 2     count = 0
 3     while count < n:
 4         print('count:',count)
 5         count += 1
 6         yield count  #return
 7 
 8 
 9     new_range = range2(10)
10     r1=next(new_range)
11     print(r1)
12     r2=next(new_range)
13     print(r2)
14     new_range.__next__()
15 
16     count: 0
17     1
18     count: 1 
19     2
20     count: 2
21  
22     next(new_range) == new_range.__next__()  #注意了

yield 和 return 的区别:
return 返回 并终止 function
yield 返回数据,并冻结当前的执行过程,要想启动就得next(),next()唤醒冻结的函数执行过程,继续执行,直到遇到下一个yield

生成器:函数的每个运行过程都可以拿到,处理大文件比较合适 yield
-------------------------------------
总结yield:
1.函数有了yield之后,函数名加()就得到了一个生成器
2.函数有了yield之后,return在生成器里,代表生成器的终止 直接报错

 1 def range2(n):
 2     count = 0
 3     while count < n:
 4         print('count:',count)
 5         count += 1
 6         # return 333
 7         sign = yield count  #return
 8         if sign =='stop':
 9             print('---sign', sign)
10             break
11     return 333
12 
13 new_range = range2(3)
14 r1=next(new_range)
15 print('do sth else...')
16 new_range.send('stop')  #1.唤醒并继续执行 2。发送一个信息到生成器的内部
17 
18 next:
19   唤醒生成器,并继续执行
20 send:
21   唤醒生成器,并继续执行,并可传递消息 

---------------------------------------
6.迭代器
迭代=循环

6.1.
可迭代对象有:一类是:list tuple dict set str 另一类是:generator yield的generator function
可直接作用于for循环的对象统称为可迭代对象:Iterable 可使用isinstance() 判断一个对象是否是Iterable
>>> from collections import Iterable
>>> isinstance([1,2,3],Iterable)
True
>>> isinstance(3,Iterable)
False

生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续了。

6.2.
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Itetator.
生成器只是迭代器的一种。对象。。。
列表,字典,字符串都不是迭代器,但他们是可迭代对象
>>> from collections import Iterator
>>> isinstance([1,2,3],Iterator)
False
>>> isinstance((x for x in range(10)),Iterator)
True

6.3.
生成器都是Iterator 对象,list dict str 虽然是Iterable ,却不是Iterator
把list dict str 等Iterable变成Iterator 可以使用iter()函数 变成迭代器后有next的方法
>>> isinstance([1,2,3],Iterator)
False
>>> isinstance(iter([1,2,3]),Iterator)
True

6.4.
为什么list dict str 等数据类型不是 Iterator ?
因为python的Iterator 对象表示的是一个数据流,数据流不知道什么时候截止。iterator对象可以被next()函数调用并不断返回下一个数据,
直到没有数据时 抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现
按需计算下一个数据,所以Iterator的计算是惰性的,只是在需要返回下一个数据时它才会计算

Iterator 甚至可以表示一个无限大的数据流,例如全体自然数,而使用list是永远不可能存储全体自然数的

小结:
1.凡是可作用于for循环的对象都是Iterable(可迭代)类型
2.凡是可作用于next()函数的对象都是Iterator(迭代器)类型,它们表示一个惰性计算的序列
3.集合数据类型如list dict str 等是Iterable 但不是 Iterator ,不过可以通过iter()函数获得一个Iterator对象
python3的for循环本质上就是通过不断调用next() 函数实现的
for i in [1,2,3,4,5]:
     print(i)

# 首先获得Iterator对象:
it = iter([1, 2, 3, 4, 5])
# 循环:
while True:
     try:
           # 获得下一个值:
           x = next(it)
     except StopIteration:
          # 遇到StopIteration就退出循环
          break

------------------------------------------------------------

总结:
1.命名空间
2.闭包
3.装饰器
4.生成器
5.迭代器

posted @ 2018-02-17 20:01  Alice的小屋  阅读(270)  评论(0编辑  收藏  举报