分頁查找
#5.隨意寫一個20行以上的文件(divmod)
# 運行程序,先將內容讀到內存中,用列表存儲。
# l = []
# 提示:一共有多少頁
# 接收用戶輸入頁碼,每頁5條,僅輸出當頁的內容
def read_page(bk_list,n,endline=None):
startline = 5 * (n-1)
endline = endline+startline-1 if endline else startline + 4
# print(startline,endline)
for i in range(startline,endline+1):
print(bk_list[i],end = '')
def read_book(filename):
f = open(filename)
book_list = f.readlines()
f.close()
return book_list
book_list = read_book('tmp_file')
line_num = len(book_list)
x,y = divmod(line_num,5)
print(line_num,x,y)
# if y:
# page = x+1
# else:
# page = x
page = x+1 if y else x
print('一共有%s頁'%page)
while True:
page_num = input('請輸入您要閱讀的頁碼 : ').strip()
if page_num.isdigit():
page_num = int(page_num)
if page_num < page:
read_page(book_list,page_num)
elif page_num == page:
read_page(book_list,page_num,y)
else:
print('您輸入的內容有誤')
一、可迭代對象
可以將某個數據集內的數據“一個挨著一個的取出來”,就叫做迭代。
可迭代協議
假如我們自己寫了一個數據類型,希望這個數據類型里的東西也可以使用for被一個一個的取出來,那我們就必須滿足for的要求。這個要求就叫做“協議”。
可以被迭代要滿足的要求就叫做可迭代協議。可迭代協議的定義非常簡單,就是內部實現了__iter__方法。
可以被for循環的都是可迭代的,要想可迭代,內部必須有一個__iter__方法。
l = [1,2,3,4,5]
s = {1,2,3,4}
#索引
#for
# for i in l:
# print(i)
# for i in 50:
# print(i)
#iterable 可迭代的
#迭代
#str
#列表
#tuple
#set
#dict
#可迭代的 ——對應的標志 __iter__
# print('__iter__' in dir([1,2,3])) #判斷一個變量是不是一個可迭代的
二、迭代器
接著分析,__iter__方法做了什么事情呢?
print([1,2].__iter__())
結果
#可迭代協議
l = [1,2,3,4,5]
# for i in l:
# print(i)
# print(iter(l)) #內置函數
l.__iter__()
#iterator #迭代器
#iterator iterable
l_iterator = iter(l)
# print(set(dir(l_iterator))-set(dir(l)))
#__next__
# iter({1,2,3})
迭代器協議
既什么叫“可迭代”之后,又一個歷史新難題,什么叫“迭代器”?
雖然我們不知道什么叫迭代器,但是我們現在已經有一個迭代器了,這個迭代器是一個列表的迭代器。
我們來看看這個列表的迭代器比起列表來說實現了哪些新方法,這樣就能揭開迭代器的神秘面紗了吧?
可迭代協議——凡是可迭代的內部都有一個__iter__方法
迭代器里既有iter方法,又有next方法 ——迭代器協議
通過iter(o)得到的結果就是一個迭代器,
'''
dir([1,2].__iter__())是列表迭代器中實現的所有方法,dir([1,2])是列表中實現的所有方法,都是以列表的形式返回給我們的,為了看的更清楚,我們分別把他們轉換成集合,
然后取差集。
'''
#print(dir([1,2].__iter__()))
#print(dir([1,2]))
print(set(dir([1,2].__iter__()))-set(dir([1,2])))
結果:
{'__length_hint__', '__next__', '__setstate__'}
我們看到在列表迭代器中多了三個方法,那么這三個方法都分別做了什么事呢?
iter_l = [1,2,3,4,5,6].__iter__()
#獲取迭代器中元素的長度
print(iter_l.__length_hint__())
#根據索引值指定從哪里開始迭代
print('*',iter_l.__setstate__(4))
#一個一個的取值
print('**',iter_l.__next__())
print('***',iter_l.__next__())
在for循環中,就是在內部調用了__next__方法才能取到一個一個的值。
那接下來我們就用迭代器的next方法來寫一個不依賴for的遍歷。
l=[1,2,8,1,9,4]
l_iterator=iter(l)
print(l_iterator.__next__())
print(l_iterator.__next__())
while True:
try:
print(next(l_iterator))
except:
break
判斷是否是迭代器 和 可迭代對象的簡便方法
#迭代器 大部分都是在python的內部去使用的,我們直接拿來用就行了
#迭代器:內置__iter__和__next__方法
from collections import Iterable
from collections import Iterator
#判斷是否是迭代器 和 可迭代對象的簡便方法
# s = 'abc'
# print(isinstance(s,Iterable))
# print(isinstance(s,Iterator))
# print(isinstance(iter(s),Iterator))
map_o = map(abs,[1,2,-3,4])
#map_o = [1,2,3,4]
print(isinstance(map_o,Iterable))
print(isinstance(map_o,Iterator))
range()
#不管是一個迭代器還是一個可迭代對象,都可以使用for循環遍歷
#迭代器出現的原因 幫你節省內存
from collections import Iterable
from collections import Iterator
a = range(100)
print(isinstance(a,Iterable))
print(isinstance(a,Iterator))
為什么要有for循環
基于上面講的列表這一大堆遍歷方式,聰明的你立馬看除了端倪,于是你不知死活大聲喊道,你這不逗我玩呢么,有了下標的訪問方式,我可以這樣遍歷一個列表啊
l=[1,2,3]
index=0
while index < len(l):
print(l[index])
index+=1
#要毛線for循環,要毛線可迭代,要毛線迭代器
for循環就是基于迭代器協議提供了一個統一的可以遍歷所有對象的方法,即在遍歷之前,先調用對象的__iter__方法將其轉換成一個迭代器,然后使用迭代器協議去實現循環訪問,這樣所有的對象就都可以通過for循環來遍歷了,
#可迭代協議 : 內部實現了__iter__方法
#迭代器協議 : 內部實現了__iter__ __next__方法
#可迭代和迭代器的不同點 : 迭代器多實現了一個__next__方法
#可迭代和迭代器的相同點 : 都可以用for循環
#判斷迭代器和可迭代的方法
#第一種:判斷內部是不是實現了 __next__
#'__next__' in dir(o)
#第二種:
# from collections import Iterable #可迭代
# from collections import Iterator #迭代器
# isinstance(o,Iterable)
# isinstance(o,Iterator)
#迭代器的特點
#可以用for循環
#可以節省內存
#你只能用一次 l = [1,2,3,4]
初識生成器
我們知道的迭代器有兩種:一種是調用方法直接返回的,一種是可迭代對象通過執行iter方法得到的,迭代器有的好處是可以節省內存。
如果在某些情況下,我們也需要節省內存,就只能自己寫。我們自己寫的這個能實現迭代器功能的東西就叫生成器。
Python中提供的生成器:
1.生成器函數:常規函數定義,但是,使用yield語句而不是return語句返回結果。yield語句一次返回一個結果,在每個結果中間,掛起函數的狀態,以便下次重它離開的地方繼續執行
2.生成器表達式:類似于列表推導,但是,生成器返回按需產生結果的一個對象,而不是一次構建一個結果列表
生成器Generator:
本質:迭代器(所以自帶了__iter__方法和__next__方法,不需要我們去實現)
特點:惰性運算,開發者自定義
生成器函數
一個包含yield關鍵字的函數就是一個生成器函數。yield可以為我們從函數中返回值,但是yield又不同于return,return的執行意味著程序的結束,調用生成器函數不會得到返回的具體的值,而是得到一個可迭代的對象。每一次獲取這個可迭代對象的值,就能推動函數的執行,獲取新的返回值。直到函數執行結束。
import time
def genrator_fun1():
a = 1
print('現在定義了a變量')
yield a
b = 2
print('現在又定義了b變量')
yield b
g1 = genrator_fun1()
print('g1 : ',g1) #打印g1可以發現g1就是一個生成器
print('-'*20) #我是華麗的分割線
print(next(g1))
time.sleep(1) #sleep一秒看清執行過程
print(next(g1))
生成器有什么好處呢?就是不會一下子在內存中生成太多數據
假如我想讓工廠給學生做校服,生產2000000件衣服,我和工廠一說,工廠應該是先答應下來,然后再去生產,我可以一件一件的要,也可以根據學生一批一批的找工廠拿。
而不能是一說要生產2000000件衣服,工廠就先去做生產2000000件衣服,等回來做好了,學生都畢業了。。。
初識生成器二
def produce():
"""生產衣服"""
for i in range(2000000):
yield "生產了第%s件衣服"%i
product_g = produce()
print(product_g.__next__()) #要一件衣服
print(product_g.__next__()) #再要一件衣服
print(product_g.__next__()) #再要一件衣服
num = 0
for i in product_g: #要一批衣服,比如5件
print(i)
num +=1
if num == 5:
break
#到這里我們找工廠拿了8件衣服,我一共讓我的生產函數(也就是produce生成器函數)生產2000000件衣服。
#剩下的還有很多衣服,我們可以一直拿,也可以放著等想拿的時候再拿
讀取文件
import time
def tail(filename):
f = open(filename)
f.seek(0, 2) #從文件末尾算起
while True:
line = f.readline() # 讀取文件中新的文本行
if not line:
time.sleep(0.1)
continue
yield line
tail_g = tail('tmp')
for line in tail_g:
print(line)
計算移動平均值‘
#計算移動平均值
#7日平均年化收益
#10,12,11 = (10+12+11)/3
#total = 10 + 12 + 11
#day = 1 + 1 + 1
#avg = 10/1 22/2 33/3
# 10 11 11
def averager():
total = 0
day = 0
avrage = 0
while True:
day_num = yield avrage #return avrage
total += day_num
day += 1
avrage = total/day
# avg = averager()
# num = next(avg) #激活生成器 avg.send(),什么都不send和next效果一樣
# print(avg.send(10)) #傳值 next
# print(avg.send(20))
__author__ = 'Administrator'
def wapper(fun):
def inner(*args,**kwargs):
g=fun(*args,**kwargs)
next(g)
return g
return inner
@wapper
def aa():
day=0
total=0
avrage =0
while True:
day_num=yield avrage
total+=day_num
day+=1
avrage=total/day
g=aa()
print(g.send(20))
yield from
# __author__ = 'Administrator'
# def fun():
# for i in "ab":
# yield i
# print("....")
# yield 1
#
# aa=fun()
# while True:
# try:
# print(next(aa))
# except:
# break
# print(next(aa))
def fun():
yield from "abc"
yield from [1,2,4,5]
aa=fun()
print(next(aa))
print(aa.__next__())
print(next(aa))
print(aa.__next__())
while True:
try:
print(next(aa))
except:
break
n = yield r //yield,放棄本函數的執行,同時把r的值返回給調用者send()。 n的值就是send(n)的參數值
r = c.send(n) //r的值就是yield的參數值。
next()讓包含yield的函數(Generator)執行
next()和send()在一定意義上作用是相似的,區別是send()可以傳遞值給yield表達式,而next()不能傳遞特定的值,只能傳遞None進去。因此,我們可以看做
c.next() 和 c.send(None) 作用是一樣的。
第一次調用時,請使用next()語句或是send(None),不能使用send發送一個非None的值,否則會出錯的,因為沒有yield語句來接收這個值。
1
2
3
4
5
6
def x():
print 'bai wei'
m = yield 5
print m
d = yield 12
print 'reach here '
c = x()
c.next() //啟動generator
c.next() //給yield表達式傳一個None值
輸出
bai wei
None
c = x()
c.next() /啟動generator,運行到第一個yield處停止
c.send('hi') //從停止的yield處繼續運行,并把值hi傳過去
輸出
bai wei
hi
c = x()
c.send('hi') //出錯,generator還沒啟動
輸出
Traceback (most recent call last):
File "yield.py", line 36, in
c.send('hi')
TypeError: can't send non-None value to a just-started generator
5. send(msg) 與 next()的返回值
send(msg) 和 next()是有返回值的,它們的返回值很特殊,返回的是下一個yield表達式的參數。比如yield 5,則返回 5 。到這里,是不是明白了一些什么東西?本文第一個例子中,通過for i in alist 遍歷 Generator,其實是每次都調用了alist.Next(),而每次alist.Next()的返回值正是yield的參數,即我們開始認為被壓進去的東東。我們再延續上面的例子:
def h():
print 'Wen Chuan',
m = yield 5
print m
d = yield 12
print 'We are together!'
c = h()
m = c.next() #m 獲取了yield 5 的參數值 5
d = c.send('Fighting!') #d 獲取了yield 12 的參數值12
print 'We will never forget the date', m, '.', d
輸出結果:
Wen Chuan Fighting!
We will never forget the date 5 . 12
列表推導式和生成器表達式
#老男孩由于峰哥的強勢加盟很快走上了上市之路,alex思來想去決定下幾個雞蛋來報答峰哥
egg_list=['雞蛋%s' %i for i in range(10)] #列表解析
#峰哥瞅著alex下的一筐雞蛋,捂住了鼻子,說了句:哥,你還是給我只母雞吧,我自己回家下
laomuji=('雞蛋%s' %i for i in range(10))#生成器表達式
print(laomuji)
print(next(laomuji)) #next本質就是調用__next__
print(laomuji.__next__())
print(next(laomuji))
# for i in range(100):
# print(i*i)
# l =[i*i for i in range(100)]
# print(l)
# l = [{'name':'v','age':28},{'name':'v'}]
# name_list = [dic['name'] for dic in l]
# print(name_list)
# l = [{'name':'v1','age':28},{'name':'v2'}]
# name_list_generator = (dic['name'] for dic in l)
# print(name_list_generator)
# print(next(name_list_generator))
# print(next(name_list_generator))
# egg_list=['雞蛋%s' %i for i in range(10)]
# print(egg_list)
# laomuji = ('雞蛋%s' %i for i in range(1,11))
# print(laomuji)
# print(next(laomuji))
# print(next(laomuji))
# print(sum([1,2,3]))
# print(sum(range(1,4)))
def func():
# yield from 'ABC'
for i in 'ABC':
yield i
# g = func()
# print(next(g))
# print(next(g))
for i in range(10):
print(i)
[i for i in range(10)]
a = 10
b=20
if a >b :
print(a)
else:
print(b)
a if a>b else b
一、復習
迭代器:擁有__iter__,__next__;
怎樣從迭代器中取值:_next 和 for
生成器:
自己定義一個能實現迭代器功能的函數就是生成器
生成器函數:帶yield的函數,調用生成器函數,不會執行函數中的任何功能,只是返回一個生成器,調用next、時才執行函數中內容,遇到yield停止,并返回yield的值
send方法就是向函數中傳值,把值賦給yield對應的變量,同時還執行next方法
一個要用send方法的生成器函數中至少要有兩個yield、
一個生成器函數中有多少個yield就可以調用多少個(next+send)方法、
生成器的激活只能用next方法
#2.生成器表達式
#new_g = (i*i for i in range(100)) #new_g是一個生成器表達式
二、作業
讀文件,找帶關鍵字的行
# 3.處理文件,用戶指定要查找的文件和內容
# 將文件中包含要查找內容的每一行都輸出到屏幕
def read(fname,str):
with open(fname,encoding="utf-8")as f:
l=f.readlines();
for i in l:
if str in i:
yield i
aa=read("1","奧特曼")
for i in aa:
print(i)
、進階版本
__author__ = 'Administrator'
def init(fun):
def inner(*args,**kwargs):
g=fun(*args,**kwargs)
next(g)
return g
return inner
@init
def read(g_read_line):
while True:
fname=yield
str=yield
with open(fname,encoding="utf-8")as f:
l=f.readlines()
for line in l:
if str in line:
g_read_line.send(line)
@init
def read_line():
while True:
line=yield
if line:print(line)
g_read=read(read_line())
g_read.send("1")
g_read.send("奧特曼")
列表推倒式和生成器表達式
new_l = []
for i in range(100):
new_l.append(i*i)
#list(range(100))
new_l = [i*i for i in range(100)]
new_l = (i*i for i in range(100)) #生成器表達式
生成器相關面試題
# def demo():
# for i in range(4):
# yield i
# g=demo()
# g1=(i for i in g)
# g2=(i for i in g1)
# print(list(g2))
# print(list(g1))
def add(n,i):
return n+i
def test():
for i in range(4):
yield i
g=test()
for n in [1,10]:
g=(add(n,i) for i in g)
# # g=(add(n,i) for i in g)
# n = 10
# g=(add(n,i) for i in (add(n,i) for i in g))
# print(list(g))
# for i in [1,2]:
# pass
#
# print(i)
import os
def init(func): #預激活生成器的一個裝飾器
def wrapper(*args,**kwargs):
g=func(*args,**kwargs) #func是一個生成器函數,返回的g是一個生成器
next(g) #預激活生成器
return g #返回激活后的生成器g
return wrapper
@init #list_files = init(list_files) == wrapper
def list_files(target): #target = opener_g
while 1:
dir_to_search=yield
for top_dir,dir,files in os.walk(dir_to_search): #os.walk (路徑,文件夾,文件)
for file in files: #從文件列表中獲取一個一個的文件
target.send(os.path.join(top_dir,file)) #把文件的絕對路徑傳給了opener_g
@init #opener = init(opener) == wrapper
def opener(target): #target = cat_g
while 1:
file=yield #拿到了一個文件的路徑
fn=open(file,encoding='utf-8') #打開文件獲取了一個文件句柄
target.send((file,fn)) #cat_g發送了一個文件的路徑和句柄
@init #cat = init(cat) == wrapper
def cat(target): #target = grep_g
while 1:
file,fn=yield #文件路徑和文件的句柄
for line in fn:
target.send((file,line)) #文件路徑,文件中的一行
@init #grep = init(grep) == wrapper
def grep(pattern,target): #要搜索的關鍵字,printer_g
lst = []
while 1:
file,line=yield #文件的路徑和每一行
if pattern in line and file not in lst: #判斷關鍵字是否在當前行
lst.append(file)
target.send(file) #printer_g.send文件路徑
@init #printer = init(printer) == wrapper
def printer():
while 1:
file=yield #獲取一個文件路徑
if file:
print(file) #打印文件的路徑:文件里包含了要搜索的關鍵字
g=list_files(opener(cat(grep('python',printer()))))
# g=list_files(opener(cat(grep('python',printer_g))))
# g=list_files(opener(cat(grep_g)))
# g=list_files(opener(catg)))
# g=list_files(opener_g)
g.send('D:\Python代碼文件存放目錄\S6\day18')
#用戶給一個路徑和關鍵字
#可以從一個文件路徑中找到所有包含關鍵字的文件
二、匿名函數、
匿名函數 簡單的需要用函數去解決的問題 匿名函數的函數體 只有一行也叫lambda表達式
# cal2 = lambda n : n*n
# ret = cal2(20)
# print(ret)
# def add(x,y):return x+y
# add2 = lambda x,y : x+y
# ret = add2(1,2)
# print(ret)
print(max(dic))
func = lambda k:dic[k]
print(max(dic,key = func))
print(max(dic,key=lambda k:dic[k]))
l = [1,2,3,4]
d=lambda x:x*x
print(list(map(d,l)))
l = [10,11,8,12]
# def func(x):
# return x>10
# print(list(filter(func,l)))
# print(list(filter(lambda x:x>10,l)))
#現有兩個元組(('a'),('b')),(('c'),('d')),請使用python中匿名函數生成列表[{'a':'c'},{'b':'d'}]
t1 = (('a'),('b'))
t2 = (('c'),('d'))
print(list(zip(t1,t2)))
c=lambda t:{t[0]:t[1]}
d=map(c,zip(t1,t2))
print (list(d))
d=list(map(lambda z:{z[0],z[1]},zip(t1,t2)))
print(d)
l=[i for i in range(100) if i%3==0]
print(l)
print(len(l))
# names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
# ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
# print([name for lst in names for name in lst if name.count('e') >=2])
mcase = {'a': 10, 'b': 34}
for i in mcase:
print(i)
[i for i in mcase]
print({key:key+'1' for key in mcase})
print({key:mcase[key] for key in mcase})
print({mcase[key]:key for key in mcase})
mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3}
mcase_frequency = {k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0) for k in mcase}
print(mcase_frequency)