1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
1. 名称空间
 
python有三种名称空间
内置名称空间: 随着python解释器的启动而产生
print ( sum )
print ( max )
 
全局名称空间: 文件的执行会产生全局名称空间,指的是文件级别的定义名字都会放入该空间
=  11
if  = =  11 :
     print (x)
 
局部名称空间: 调用函数时会产生局部名称空间,只在函数调用时临时绑定,调用结束时解绑
=  1000
def  foo():
     =  1
     print (x)
foo()
print (x)
 
作用域:
     1. 全局作用域: 内置名称空间,全局名称空间,全局有效,在任何位置都能被访问到,
     除非 del 删除,否则存活到文件结束。
     2. 局部作用域: 局部名称空间,局部有效,只能在局部范围调用,调用结束失效。
 
名字的查找顺序: 局部名称空间 - - >全局名称空间 - - >内置名称空间
=  1000
def  func():
     =  2
     print ( locals ())     #locals()查看局部作用域内的名字
print ( globals ())     #globals()查看全局作用域内的名字
 
 
2. 函数对象
     1. 可以被引用
     2. 可以当作参数传递
     3. 返回值可以是函数
     4. 可以当作容器类型的元素
     
  例子:
      def  foo():
          print ( "from foo" )
      func  =  foo
      print (foo)
      print (func)
      foo()
      func()
      
      def  foo():
          print ( "from foo" )
      def  bar(func):
          print (func)
          func()
      bar(foo)
      
      def  foo():
          print ( "from foo" )
      dic  =  { 'func' : foo}
      print (dic[ 'func' ])
      dic[ 'func' ]()
      
      
      
3. 闭包函数
     闭包:
       1. 定义在内部函数
       2. 包含对外部作用域而非全局作用域的引用
   该内部函数就称作闭包函数
   例子:
   def  f1():
     =  1
     def  f2():      #f2称作闭包函数
       print (x)
     return  f2
   =  f1()
   print (f)    #打印f2函数的内存地址
   f()     #打印1
  
    例子:
    from  urllib.request  import  urlopen
    def  index(url):
        def  get():
            return  urlopen(url).read()
        return  get
    oldboy  =  index( 'http://www.baidu.com' )
    print (oldboy().decode( 'utf-8' ))
    print (oldboy.__closure__[ 0 ].cell_contents)     #打印外部引用而非全局引用对象
    
4. 装饰器
     修饰其他对象的工具,修饰添加功能,工具指的是函数。
     装饰器本身是任何可调用对象,被装饰的对象也可以是任何可调用的对象。
     
     为什么要用装饰器?
     开放封闭原则,对修改是封闭的,对扩展是开放的。
     装饰器就是为了在不修改被装饰对象源代码以及调用方式的前提下,为其添加新功能
     
     装饰器相当于闭包的实现
     
     例子:
     import  time
     def  timmer(func):
         def  wrapper( * args,  * * kwargs):
             start_time  =  time.time()
             res  =  func( * args,  * * kwargs)
             stop_time  =  time.time()
             print ( "run time is {0}" . format (stop_time  -  start_time))
         return  wrapper
         
     @timmer         #相当于index = timmer(index)
     def  index():
         time.sleep( 3 )
         print ( "welcome to index" )
         return  1
         
     index()     #其实相当于执行了timmer(index)
     
     例子:
     import  time
     def  timmer(func):
         def  wrapper( * args,  * * kwargs):
             start_time  =  time.time()
             res  =  func( * args,  * * kwargs)
             stop_time  =  time.time()
             print ( "run time is {0}" . format (stop_time  -  start_time))
         return  wrapper
         
     def  index():
         time.sleep( 3 )
         print ( "welcome to index" )
     
     =  timmer(index)
     print (f)
     f()         #f()<=====>wrapper()
     
     
     认证用户登录
     login_user  =  { 'user' None 'status' False }
     def  auth(func):
         def  wrapper( * args,  * * kwargs):
             if  login_user[ 'user' and  login_user[ 'status' ]:
                 res  =  func( * args,  * * kwargs)
                 return  res
             else :
                 name  =  input ( "请输入姓名:" )
                 passwd  =  input ( "请输入密码:" )
                 if  name  = =  "hyh"  and  passwd  = =  "123" :
                     login_user[ 'user' =  "hyh"
                     login_user[ 'status' =  True
                     print ( "\033[45mlogin successful\033[0m" )
                     res  =  func( * args,  * * kwargs)
                     return  res
                 else :
                     print ( "\033[45mlogin err\033[0m" )
         return  wrapper
         
    @auth
    def  index():
        print ( "welcome to index page" )
        
    @auth
    def  home(name):
        print ( "%s welcome to home page"  %  (name)) 
        
    index()
    home( "hyh" )
    
5. 迭代器
     迭代器的概念: 重复上一次迭代的结果为下一次迭代的初始值,重复的过程称为迭代,
     每次重复即一次迭代
     
     为什么要有迭代器?
     对于没有索引的数据类型,必须提供一种不依赖索引的迭代方式
     
     可迭代对象: 内置__iter__方法的都是可迭代对象
     [ 1 , 2 ].__iter__()
     'hello' .__iter__()
     ( 1 , 2 ).__iter__()
     { "a" : 1 "b" 2 }.__iter__()
     { 1 , 2 , 3 }.__iter__()
     
     迭代器: 执行__iter__()方法,得到的结果就是迭代器,迭代器有__next__()方法
     =  [ 1 , 2 , 3 ].__iter__()
     print (i.__next__())         #打印1
     print (i.__next__())         #打印2
     print (i.__next__())         #打印3
     print (i.__next__())     #抛出异常
     
     i__iter__() < = = > iter (i)
     i__next__() < = = > next (i)
     
     如何判断一个对象是可迭代对象,还是迭代器对象
     from  collections  import  Iterable, Iterator
     print ( isinstance ( 'abc' ,Iterable))
     print ( isinstance ([],Iterable))
     print ( isinstance ((),Iterable))
     print ( isinstance ({ 'a' : 1 },Iterable))
     print ( isinstance ({ 1 , 2 },Iterable))
     f = open ( 'a.txt' , 'w' )
     f.__iter__()
     print ( isinstance (f,Iterable))     #只有文件是迭代器对象
     
     可迭代对象:只有__iter__方法,执行该方法得到的迭代器对象
     迭代协议:
         对象有__next__
         对象有__iter__,对于迭代器对象来说,执行__iter__方法,得到的结果仍然是它本身
         
     迭代器的优点和缺点
         优点:
             1. 提供了一种不依赖下标的迭代方式
             2. 就跌迭代器本身来说,更节省内存
 
         缺点:
             1.  无法获取迭代器对象的长度
             2.  不如序列类型取值灵活,是一次性的,只能往后取值,不能往前退
             
6. 生成器
     生成器函数: 只要函数体包含 yield 关键字,该函数就是生成器函数,生成器就是迭代器
     例子:
         def  foo():
             print ( "first" )
             yield  1
             print ( "second" )
             yield  2
             print ( "third" )
             yield  3
             print ( "fourth" )
         =  foo()
         for  in  g:
             print (i)
             
         print ( next (g))     #出发迭代器g的执行,进而出发函数
         print ( next (g))
         
         yield 的功能:
             1. 相当于为函数封装好__iter__和__next__函数
             2.return 只能返回一次值就终止了
             3.yield 能返回多次值,每次返回将函数暂停,下一次 next 从上一次暂停的位置继续
             
             
         模拟tail  - f |grep  "python"
         例子:
             import  time
             def  tail( file ):
                 with  open ( file , encoding = 'utf-8' ) as f:
                     line  =  f.readline().strip()
                     if  line:
                         yield  line
                     else :
                         time.sleep( 0.2 )
             =  tail( 'a.txt' )
             for  line  in  t:
                 print (line)
                 
             def  grep(pattern, lines):
                         for  line  in  lines:
                             if  pattern  in  line:
                                 yield  line
                     =  grep( "python" , tail( 'one.py' ))
                     print (g)
                     for  in  g:
                         print (i)
     
     yield 两种用法
     1. 语句形式:  yield  1
     2. 表达式用法: x  =  yield
     
     例子:
         def  deco(func):
             def  wrapper( * args,  * * kwargs):
                 res  =  func( * args,  * * kwargs)
                 next (res)         #相当于res.send(None)初始化生成器
                 return  res
             return  wrapper
             
         @deco
         def  eater(name):
             print ( "%s ready to eat"  % name)
             food_list  =  []
             while  True :
                 food  =  yield  food_list
                 food_list.append(food)
                 print ( '%s start to eat %s'  % (name, food))
                 
         =  eater( 'alex' )
         =  g.send( "脚趾头" )         #返回food_list列表
             print (v)        
         #send()函数发送数据给yield,跟next作用很相似,只是它能发送数据