Python Day4

一、上节补充  

匿名函数

匿名函数就是不需要显式的指定函数

1 f = lambda x:x*x
2 print(f(9))

X就是形参

1 res = map(lambda x:x**2,[1,5,7,4,8])
2 for i in res:
3     print(i)
4 #输出
5 # 1
6 # 25
7 # 49
8 # 16
9 # 64

就是将列表[1,5,7,4,8]中每一个元素进行平方运算再返回

内置参数

内置参数详解 https://docs.python.org/3/library/functions.html?highlight=built#ascii

 1 __author__ = "Alex Li"
 2 
 3 print( all([1,-5,3]) )
 4 print( any([]) )
 5 a= ascii([1,2,"开外挂开外挂"])
 6 print(type(a),[a])
 7 a = bytes("abcde",encoding="utf-8")
 8 b = bytearray("abcde",encoding="utf-8")
 9 print( b[1] )
10 b[1]= 50
11 print(b)
12 
13 
14 print(a.capitalize(),a)
15 def sayhi():pass
16 print( callable(sayhi) )
17 
18 code = '''
19 def fib(max): 10
20  n, a, b = 0, 0, 1
21  while n < max: n<10
22      print(b)
23      yield b
24      a, b = b, a + b
25      a = b     a =1, b=2, a=b , a=2,
26       b = a +b b = 2+2 = 4
27      n = n + 1
28  return '---done---'
29 
30 f= fib(10)
31 g = fib(6)
32 while True:
33  try:
34      x = next(g)
35      print('g:', x)
36  except StopIteration as e:
37      print('Generator return value:', e.value)
38      break
39 
40 '''
41 
42 py_obj = compile(code,"err.log","exec")
43 exec(py_obj)
44 
45 exec(code)
46 
47 
48 def sayhi(n):
49   print(n)
50   for i in range(n):
51       print(i)
52 sayhi(3)
53 
54 (lambda n:print(n))(5)
55 calc = lambda n:3 if n<4 else n
56 print(calc(2))
57 
58 res = filter(lambda n:n>5,range(10))
59 res = map(lambda n:n*2,range(10))
60 res = [ lambda i:i*2 for i in range(10)]
61 import functools
62 res = functools.reduce( lambda x,y:x*y,range(1,10 ))
63 print(res )
64 
65 a = frozenset([1,4,333,212,33,33,12,4])
66 print(globals())
67 
68 def test():
69  local_var =333
70  print(locals())
71  print(globals())
72 test()
73 print(globals())
74 print(globals().get('local_var'))
75 
76 
77 a = {6:2,8:0,1:4,-5:6,99:11,4:22}
78 
79 print(  sorted(a.items()) )
80 print(  sorted(a.items(),key=lambda x:x[1]) )
81 print(a )
82 
83 a = [1,2,3,4,5,6]
84 b = ['a','b','c','d']
85 
86 for i in zip(a,b):
87  print(i)
88 
89 #import 'decorator'
90 __import__('decorator')
测试代码

二、本节内容  

列表生成式,迭代器&生成器

列表生成式

1 >>> a = [i+1 for i in range(10)]
2 >>> a
3 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

生成器

通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:

1 >>> L = [x * x for x in range(10)]
2 >>> L
3 [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
4 >>> g = (x * x for x in range(10))
5 >>> g
6 <generator object <genexpr> at 0x1022ef630>

创建Lg的区别仅在于最外层的[]()L是一个list,而g是一个generator。

我们可以直接打印出list的每一个元素,但我们怎么打印出generator的每一个元素呢?

如果要一个一个打印出来,可以通过next()函数获得generator的下一个返回值:

1 >>> next(g)
2 0
3 >>> next(g)
4 1
5 。。。。。
6 >>> next(g)
7 Traceback (most recent call last):
8   File "<stdin>", line 1, in <module>
9 StopIteration

我们讲过,generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。

当然,上面这种不断调用next(g)实在是太变态了,正确的方法是使用for循环,因为generator也是可迭代对象:

1 >>> g = (x * x for x in range(10))
2 >>> for n in g:
3 ...     print(n)
4 ... 
5 0
6 。。。
7 81

所以,我们创建了一个generator后,基本上永远不会调用next(),而是通过for循环来迭代它,并且不需要关心StopIteration的错误。

generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。

比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:

1, 1, 2, 3, 5, 8, 13, 21, 34, ...

斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:

1 def fib(max): #10
2     n, a, b = 0, 0, 1
3     while n < max: #n<10
4         print(b)
5         a, b = b, a + b
6         n = n + 1
7     return '---done---'

注意,赋值语句:

a, b = b, a + b

相当于:

t = (b, a + b) # t是一个tuple
a = t[0]
b = t[1]

但不必显式写出临时变量t就可以赋值。

上面的函数可以输出斐波那契数列的前N个数:

>>> fib(6)
1
1
2
3
5
8
'done'

仔细观察,可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。

也就是说,上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print(b)改为yield b就可以了:

1 def fib(max):
2     n, a, b = 0, 0, 1
3     while n < max:
4         yield b
5         a, b = b, a + b
6         n = n + 1
7     return 'done'

这就是定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator:

>>> f = fib(6)
>>> f
<generator object fib at 0x104feaaa0>

这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

 1 #!/usr/bin/env python3
 2 # -*- coding: utf-8 -*-
 3 def quqian(money):
 4     while money > 0:
 5         money -=100
 6         yield 100
 7         print("又来取钱了,傻Ⅹ")
 8 a=quqian(1000)
 9 print(a.__next__())
10 print(a.__next__())
11 print("买东西")
12 print(a.__next__())
13 print(a.__next__())
14 print(a.__next__())
15 print(a.__next__())
16 print(a.__next__())
17 print(a.__next__())
18 print(a.__next__())
19 print(a.__next__())

异步并发

 1 #!/usr/bin/env python3
 2 # -*- coding: utf-8 -*-
 3 import time
 4 def chihuo(name):
 5     print("开始吃烧饼了!")
 6     while True:
 7         sb=yield
 8         print("{0}吃烧饼{1}了".format(name,sb))
 9         print("{}吃完了".format(name))
10 def zuo(name2):
11     a=chihuo("小明")
12     b=chihuo("小聪")
13     a.__next__()
14     b.__next__()
15     print("{}开始做烧饼了".format(name2))
16     for i in range(1,11):
17         time.sleep(2)
18         print("做了两个烧饼")
19         a.send(i)
20         b.send(i)
21 zuo("厨子")

练习

杨辉三角定义如下:

1           1
2         1   1
3       1   2   1
4     1   3   3   1
5   1   4   6   4   1
6 1   5   10  10  5   1

把每一行看做一个list,试写一个generator,不断输出下一行的list:

 1 #!/usr/bin/env python3
 2 # -*- coding: utf-8 -*-
 3 # Author:Breakering
 4 #           1
 5 #         1   1
 6 #       1   2   1
 7 #     1   3   3   1
 8 #   1   4   6   4   1
 9 # 1   5   10  10  5   1
10 
11 def triangle():
12     l = [1]
13     while True:
14         yield l
15         l.append(0)
16         l = [l[i]+l[i-1] for i in range(len(l))]
17 
18 count = 0
19 for i in triangle():
20     if count < 10:print(i)
21     else:break
22     count+=1

结果如下:

 1 [1]
 2 [1, 1]
 3 [1, 2, 1]
 4 [1, 3, 3, 1]
 5 [1, 4, 6, 4, 1]
 6 [1, 5, 10, 10, 5, 1]
 7 [1, 6, 15, 20, 15, 6, 1]
 8 [1, 7, 21, 35, 35, 21, 7, 1]
 9 [1, 8, 28, 56, 70, 56, 28, 8, 1]
10 [1, 9, 36, 84, 126, 126, 84, 36, 9, 1]

小结

generator是非常强大的工具,在Python中,可以简单地把列表生成式改成generator,也可以通过函数实现复杂逻辑的generator。

要理解generator的工作原理,它是在for循环的过程中不断计算出下一个元素,并在适当的条件结束for循环。对于函数改成的generator来说,遇到return语句或者执行到函数体最后一行语句,就是结束generator的指令,for循环随之结束。

请注意区分普通函数和generator函数,普通函数调用直接返回结果:

1 >>> r = abs(6)
2 >>> r
3 6

generator函数的“调用”实际返回一个generator对象:

1 >>> g = fib(6)
2 >>> g
3 <generator object fib at 0x1022ef948>

生成器笔记:

  1. 只有在调用时才会生成相应的数据
  2. 只记录当前位置
  3. 只有一个__next__()方法

迭代器

我们已经知道,可以直接作用于for循环的数据类型有以下几种:

一类是集合数据类型,如listtupledictsetstr等;

一类是generator,包括生成器和带yield的generator function。

这些可以直接作用于for循环的对象统称为可迭代对象:Iterable

可以使用isinstance()判断一个对象是否是Iterable对象:

>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False

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

可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator

可以使用isinstance()判断一个对象是否是Iterator对象:

>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False

生成器都是Iterator对象,但listdictstr虽然是Iterable,却不是Iterator

listdictstrIterable变成Iterator可以使用iter()函数:

>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True

你可能会问,为什么listdictstr等数据类型不是Iterator

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

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

小结

凡是可作用于for循环的对象都是Iterable类型;

凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

集合数据类型如listdictstr等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

Python的for循环本质上就是通过不断调用next()函数实现的,例如:

for x in [1, 2, 3, 4, 5]:
    pass

实际上完全等价于:

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

装饰器

装饰器:

定义:本质是函数,(装饰其他函数)就是为其他函数添加附加功能
原则:1.不能修改被装饰的函数的源代码
   2.不能修改被装饰的函数的调用方式

实现装饰器知识储备:
     1.函数即“变量”
     2.高阶函数
     a:把一个函数名当做实参传给另外一个函数
    (在不修改被装饰函数源代码的情况下为其添加功能)
     b:返回值中包含函数名
    (不修改函数的调用方式)
     3.嵌套函数

高阶函数 + 嵌套函数 ===》 装饰器

 1 import time
 2 def timmer(func):
 3     def warpper(*args,**kwargs):
 4         start_time=time.time()
 5         func()
 6         stop_time=time.time()
 7         print('the func run time is %s' %(stop_time-start_time))
 8     return warpper
 9 
10 @timmer
11 def test1():
12     time.sleep(3)
13     print('in the test1')
14 
15 test1()
装饰器预览

函数即变量理解:

前奏1

 1 #函数即变量
 2 
 3 #示范一:
 4 # def foo():
 5 #     print('in the foo')
 6 # foo()
 7 
 8 #示范二:
 9 def bar():
10     print('in the bar')
11 def foo():
12     print('in the foo')
13     bar()
14 foo()
15 
16 #示范三:
17 def foo():
18     print('in the foo')
19     bar()
20 def bar():
21     print('in the bar')
22 foo()
23 
24 #示范四:
25 # def foo():
26 #     print('in the foo')
27 #     bar()
28 #foo()
29 # def bar():
30 #     print('in the bar')
View Code

前奏2

 1 # import time
 2 # def bar():
 3 #     time.sleep(3)
 4 #     print('in the bar')
 5 #
 6 # def test1(func):
 7 #     start_time=time.time()
 8 #     func()    #run bar
 9 #     stop_time=time.time()
10 #     print("the func run time is %s" %(stop_time-start_time))
11 #
12 # test1(bar)
13 # bar()
14 
15 
16 # x=1
17 # y=x
18 #
19 # func=bar
20 # func()
21 
22 import time
23 def bar():
24     time.sleep(3)
25     print('in the bar')
26 def test2(func):
27     print(func)
28     return func
29 
30 # print(test2(bar))
31 bar=test2(bar)
32 bar()  #run bar
View Code

前奏3

1 def foo():
2     print('in the foo')
3     def bar():
4         print('in the bar')
5 
6     bar()
7 foo()
View Code

正题

 1 import time
 2 def timer(func): #timer(test1)  func=test1
 3     def deco(*args,**kwargs):
 4         start_time=time.time()
 5         func(*args,**kwargs)   #run test1()
 6         stop_time = time.time()
 7         print("the func run time  is %s" %(stop_time-start_time))
 8     return deco
 9 @timer  #test1=timer(test1)
10 def test1():
11     time.sleep(1)
12     print('in the test1')
13 
14 @timer # test2 = timer(test2)  = deco  test2(name) =deco(name)
15 def test2(name,age):
16     print("test2:",name,age)
17 
18 test1()
19 test2("alex",22)

带参数的装饰器

 1 user,passwd = 'alex','abc123'
 2 def auth(auth_type):
 3     print("auth func:",auth_type)
 4     def outer_wrapper(func):
 5         def wrapper(*args, **kwargs):
 6             print("wrapper func args:", *args, **kwargs)
 7             if auth_type == "local":
 8                 username = input("Username:").strip()
 9                 password = input("Password:").strip()
10                 if user == username and passwd == password:
11                     print("33[32;1mUser has passed authentication33[0m")
12                     res = func(*args, **kwargs)  # from home
13                     print("---after authenticaion ")
14                     return res
15                 else:
16                     exit("33[31;1mInvalid username or password33[0m")
17             elif auth_type == "ldap":
18                 print("搞毛线ldap,不会。。。。")
19 
20         return wrapper
21     return outer_wrapper
22 
23 def index():
24     print("welcome to index page")
25 @auth(auth_type="local") # home = wrapper()
26 def home():
27     print("welcome to home  page")
28     return "from home"
29 
30 @auth(auth_type="ldap")
31 def bbs():
32     print("welcome to bbs  page")
33 
34 index()
35 print(home()) #wrapper()
36 bbs()

另附本人对装饰器的一些特殊理解:http://www.cnblogs.com/breakering/p/6100973.html

软件目录结构规范:

参考大王博客:http://www.cnblogs.com/alex3714/articles/5765046.html

三、作业  

有以下员工信息表

 

当然此表你在文件存储时可以这样表示

1,Alex Li,22,13651054608,IT,2013-04-01

现需要对这个员工信息文件,实现增删改查操作

  1. 可进行模糊查询,语法至少支持下面3种:
    1.   select name,age from staff_table where age > 22
    2.   select  * from staff_table where dept = "IT"
    3.       select  * from staff_table where enroll_date like "2013"
    4. 查到的信息,打印后,最后面还要显示查到的条数 
  2. 可创建新员工纪录,以phone做唯一键,staff_id需自增
  3. 可删除指定员工信息纪录,输入员工id,即可删除
  4. 可修改员工信息,语法如下:
    1.   UPDATE staff_table SET dept="Market" WHERE where dept = "IT"

 注意:以上需求,要充分使用函数,请尽你的最大限度来减少重复代码!

原文地址:https://www.cnblogs.com/breakering/p/6718049.html