Python Day4

1、上節補充  

匿名函數

匿名函數就是不須要顯式的指定函數html

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

X就是形參python

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#asciiapi

 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')
測試代碼

2、本節內容  

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

列表生成式

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。app

要建立一個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。ide

咱們能夠直接打印出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("\033[32;1mUser has passed authentication\033[0m")
12                     res = func(*args, **kwargs)  # from home
13                     print("---after authenticaion ")
14                     return res
15                 else:
16                     exit("\033[31;1mInvalid username or password\033[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

3、做業  

有如下員工信息表

 

固然此表你在文件存儲時能夠這樣表示

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"

 注意:以上需求,要充分使用函數,請盡你的最大限度來減小重複代碼!

相關文章
相關標籤/搜索