函数 - 命名空间/闭包/装饰器/生成器/迭代器
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.迭代器