三元表達式、列表推導式、生成器表達式、遞歸、內置函數、匿名函數
一、三元表達式
name=input(‘姓名>>: ‘) res=‘SB‘ if name == ‘alex‘ else ‘NB‘ print(res)
二、列表推導式和生成器表達式
#老男孩由於峰哥的強勢加盟很快走上了上市之路,alex思來想去決定下幾個雞蛋來報答峰哥 egg_list=[‘雞蛋%s‘ %i for i in range(10)] #列表解析 #峰哥瞅著alex下的一筐雞蛋,捂住了鼻子,說了句:哥,你還是給我只母雞吧,我自己回家下 laomuji=(‘雞蛋%s‘ %i for i in range(10))#生成器表達式 print(laomuji) print峰哥和alex的故事(next(laomuji)) #next本質就是調用__next__ print(laomuji.__next__()) print(next(laomuji))
總結:
1.把列表解析的[]換成()得到的就是生成器表達式
2.列表解析與生成器表達式都是一種便利的編程方式,只不過生成器表達式更節省內存
3.Python不但使用叠代器協議,讓for循環變得更加通用。大部分內置函數,也是使用叠代器協議訪問對象的。例如, sum函數是Python的內置函數,該函數使用叠代器協議訪問對象,而生成器實現了叠代器協議,所以,我們可以直接這樣計算一系列值的和:
sum(x ** 2 forx in range(4))
而不用多此一舉使用如下方式
sum([x ** 2 for x in range(4)])
三、遞歸
1. 遞歸調用的定義
遞歸調用是函數嵌套調用的一種特殊形式,函數在調用時,直接或間接調用了自身,就是遞歸調用
2. 遞歸的最大深度-997
一個簡單的故事:從前有個山,山裏有座廟,廟裏老和尚講故事, 講的什麽呢?這個故事我們可以一直講下去
def story(): s = """ 從前有個山,山裏有座廟,廟裏老和尚講故事, 講的什麽呢? """ print(s) story() story()
可以看出如果遞歸函數沒有遇到外力的阻止,會一直進行下去,而函數的執行,會不斷的在內存中開辟名稱空間,而處於一個無限調用開辟的過程中,而造成內存不足,python為了杜絕此類事情的發生,強制將遞歸的層數限制在997,如下可以測試得知
def foo(n): print(n) n += 1 foo(n) foo(1)測試遞歸最大深度
由此可見未報錯之前是997,為了實現我們程序的優化而設置為997,當然此值是可以更改的
import sys print(sys.setrecursionlimit(100000))修改遞歸最大深度
此處說明一點,如果遞歸深度為997都沒有得到你的程序想要的結果,則說明你的程序寫的確實比較爛。。。
看到此處我們或許覺得遞歸沒有while True好用,江湖人稱:人理解循環,神理解遞歸,所以不容小看遞歸,之後的很多算法都和遞歸有關,所以必須掌握遞歸。
3. 理解遞歸的思想
現在你們問我,alex老師多大了?我說我不告訴你,但alex比 egon 大兩歲。
你想知道alex多大,你是不是還得去問egon?egon說,我也不告訴你,但我比武sir大兩歲。
你又問武sir,武sir也不告訴你,他說他比金鑫大兩歲。
那你問金鑫,金鑫告訴你,他40了。。。
這個時候你是不是就知道了?alex多大?
我們用等式來說明這個問題
age(4) = age(3) + 2 age(3) = age(2) + 2 age(2) = age(1) + 2 age(1) = 40
對於這樣的情況我們用函數如何表現呢?
def foo(n): if n==1: return 40 else: return foo(n-1)+2 print(foo(4))
4. 總結遞歸調用
1. 必須有一個明確的結束條件
2. 每次進入更深一層遞歸時,問題規模相比上次遞歸都應有所減少
3. 遞歸效率不高,遞歸層次過多會導致棧溢出(在計算機中,函數調用是通過棧(stack)這種數據結構實現的,每當進入一個函數調用,棧就會加一層棧幀,每當函數返回,棧就會減一層棧幀。由於棧的大小不是無限的,所以,遞歸調用的次數過多,會導致棧溢出)
四、內置函數
#註意:內置函數id()可以返回一個對象的身份,返回值為整數。這個整數通常對應與該對象在內存中的位置,但這與python 的具體實現有關,不應該作為對身份的定義,即不夠精準,最精準的還是以內存地址為準。is運算符用於比較兩個對象的身份, 等號比較兩個對象的值,內置函數type()則返回一個對象的類型 #更多內置函數:https://docs.python.org/3/library/functions.html?highlight=built#ascii
上面就是內置函數的表,68個函數都在這兒了。這個表的順序是按照首字母的排列順序來的,你會發現都混亂的堆在一起。比如,oct和bin和hex都是做進制換算的,但是卻被寫在了三個地方。。。這樣非常不利於大家歸納和學習。那我把這些函數分成了6大類。你看下面這張圖,你猜咱們今天會學哪幾大類呀?
1. 作用域關系
基於字典的形式獲取局部變量和全局變量
globals()——獲取全局變量的字典
locals()——獲取執行本方法所在命名空間內的局部變量的字典
2. 其他
#1、語法 # eval(str,[,globasl[,locals]]) # exec(str,[,globasl[,locals]]) #2、區別 #示例一: s=‘1+2+3‘ print(eval(s)) #eval用來執行表達式,並返回表達式執行的結果 print(exec(s)) #exec用來執行語句,不會返回任何值 ‘‘‘ 6 None ‘‘‘ #示例二: print(eval(‘1+2+x‘,{‘x‘:3},{‘x‘:30})) #返回33 print(exec(‘1+2+x‘,{‘x‘:3},{‘x‘:30})) #返回None # print(eval(‘for i in range(10):print(i)‘)) #語法錯誤,eval不能執行表達式 print(exec(‘for i in range(10):print(i)‘))eval和exec
compile(str,filename,kind) filename:用於追蹤str來自於哪個文件,如果不想追蹤就可以不定義 kind可以是:single代表一條語句,exec代表一組語句,eval代表一個表達式 s=‘for i in range(10):print(i)‘ code=compile(s,‘‘,‘exec‘) exec(code) s=‘1+2+3‘ code=compile(s,‘‘,‘eval‘) eval(code)complie(了解即可)
輸入輸出相關:
input() 輸入
s = input("請輸入內容 : ") #輸入的內容賦值給s變量 print(s) #輸入什麽打印什麽。數據類型是strinput用法
print() 輸出
def print(self, *args, sep=‘ ‘, end=‘\n‘, file=None): # known special case of print """ print(value, ..., sep=‘ ‘, end=‘\n‘, file=sys.stdout, flush=False) file: 默認是輸出到屏幕,如果設置為文件句柄,輸出到文件 sep: 打印多個值之間的分隔符,默認為空格 end: 每一次打印的結尾,默認為換行符 flush: 立即把內容輸出到流文件,不作緩存 """print源碼解析
f = open(‘tmp_file‘,‘w‘) print(123,456,sep=‘,‘,file = f,flush=True)file關鍵字的說明
import time for i in range(0,101,2): time.sleep(0.1) char_num = i//2 #打印多少個‘*‘ per_str = ‘\r%s%% : %s\n‘ % (i, ‘*‘ * char_num) if i == 100 else ‘\r%s%% : %s‘%(i,‘*‘*char_num) print(per_str,end=‘‘, flush=True) #小越越 : \r 可以把光標移動到行首但不換行打印進度條
數據類型相關:
type(o) 返回變量o的數據類型
內存相關:
id(o) o是參數,返回一個變量的內存地址
hash(o) o是參數,返回一個可hash變量的哈希值,不可hash的變量被hash之後會報錯。
t = (1,2,3) l = [1,2,3] print(hash(t)) #可hash print(hash(l)) #會報錯 ‘‘‘ 結果: TypeError: unhashable type: ‘list‘hash實例
hash函數會根據一個內部的算法對當前可hash變量進行處理,返回一個int數字。
*每一次執行程序,內容相同的變量hash值在這一次執行過程中不會發生改變。
文件操作相關
open() 打開一個文件,返回一個文件操作符(文件句柄)
操作文件的模式有r,w,a,r+,w+,a+ 共6種,每一種方式都可以用二進制的形式操作(rb,wb,ab,rb+,wb+,ab+)
可以用encoding指定編碼.
模塊操作相關
__import__導入一個模塊
import time
導入模塊
os = __import__(‘os‘) print(os.path.abspath(‘.‘))__import__
幫助方法
在控制臺執行help()進入幫助模式。可以隨意輸入變量或者變量的類型。輸入q退出
或者直接執行help(o),o是參數,查看和變量o有關的操作。。。
和調用相關
callable(o),o是參數,看這個變量是不是可調用。
如果o是一個函數名,就會返回True
def func():pass print(callable(func)) #參數是函數名,可調用,返回True print(callable(123)) #參數是數字,不可調用,返回Falsecallable實例
查看參數所屬類型的所有內置方法
dir() 默認查看全局空間內的屬性,也接受一個參數,查看這個參數內的方法或變量
print(dir(list)) #查看列表的內置方法 print(dir(int)) #查看整數的內置方法查看變量/數據類型的內置方法
3. 和數字相關
數字——數據類型相關:bool,int,float,complex
數字——進制轉換相關:bin,oct,hex
數字——數學運算:abs,divmod,min,max,sum,round,pow
4. 和數據結構相關
序列——列表和元組相關的:list和tuple
序列——字符串相關的:str,format,bytes,bytearry,memoryview,ord,chr,ascii,repr
ret = bytearray(‘alex‘,encoding=‘utf-8‘) print(id(ret)) print(ret[0]) ret[0] = 65 print(ret) print(id(ret))bytearray
ret = memoryview(bytes(‘你好‘,encoding=‘utf-8‘)) print(len(ret)) print(bytes(ret[:3]).decode(‘utf-8‘)) print(bytes(ret[3:]).decode(‘utf-8‘))memoryview
序列:reversed,slice
l = (1,2,23,213,5612,342,43) print(l) print(list(reversed(l)))reversed
l = (1,2,23,213,5612,342,43) sli = slice(1,5,2) print(l[sli])slice
數據集合——字典和集合:dict,set,frozenset
數據集合:len,sorted,enumerate,all,any,zip,filter,map
fileter 和 map
filter()函數接收一個函數 f 和一個list,這個函數 f 的作用是對每個元素進行判斷,返回 True或 False,filter()根據判斷結果自動過濾掉不符合條件的元素,返回由符合條件元素組成的新list。
例如,要從一個list [1, 4, 6, 7, 9, 12, 17]中刪除偶數,保留奇數,首先,要編寫一個判斷奇數的函數:
def is_odd(x): return x % 2 == 1
然後,利用filter()過濾掉偶數:
>>>filter(is_odd, [1, 4, 6, 7, 9, 12, 17])
結果:
[1, 7, 9, 17]
利用filter(),可以完成很多有用的功能,例如,刪除 None 或者空字符串:
def is_not_empty(s): return s and len(s.strip()) > 0
>>>filter(is_not_empty, [‘test‘, None, ‘‘, ‘str‘, ‘ ‘, ‘END‘])
結果:
[‘test‘, ‘str‘, ‘END‘]
註意: s.strip(rm) 刪除 s 字符串中開頭、結尾處的 rm 序列的字符。
當rm為空時,默認刪除空白符(包括‘\n‘, ‘\r‘, ‘\t‘, ‘ ‘),如下:
>>> a = ‘ 123‘ >>> a.strip() ‘123‘ >>> a = ‘\t\t123\r\n‘ >>> a.strip() ‘123‘
練習:
請利用filter()過濾出1~100中平方根是整數的數,即結果應該是:
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
方法:
import math def is_sqr(x): return math.sqrt(x) % 1 == 0 print filter(is_sqr, range(1, 101))
結果:
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
map
Python中的map函數應用於每一個可叠代的項,返回的是一個結果list。如果有其他的可叠代參數傳進來,map函數則會把每一個參數都以相應的處理函數進行叠代處理。map()函數接收兩個參數,一個是函數,一個是序列,map將傳入的函數依次作用到序列的每個元素,並把結果作為新的list返回。
有一個list, L = [1,2,3,4,5,6,7,8],我們要將f(x)=x^2作用於這個list上,那麽我們可以使用map函數處理。
>>> L = [1,2,3,4,] >>> def pow2(x): ... return x*x ... >>> map(pow2,L) [1, 4, 9, 16]
sorted
對List、Dict進行排序,Python提供了兩個方法對給定的List L進行排序,
方法1.用List的成員函數sort進行排序,在本地進行排序,不返回副本
方法2.用built-in函數sorted進行排序(從2.4開始),返回副本,原始輸入不變
--------------------------------sorted---------------------------------------
sorted(iterable, key=None, reverse=False)
Return a new list containing all items from the iterable in ascending order.
A custom key function can be supplied to customise the sort order, and the
reverse flag can be set to request the result in descending order.
-----------------------------------------------------------------------------
參數說明:
iterable:是可叠代類型;
key:傳入一個函數名,函數的參數是可叠代類型中的每一項,根據函數的返回值大小排序;
reverse:排序規則. reverse = True 降序 或者 reverse = False 升序,有默認值。
返回值:有序列表 例: 列表按照其中每一個值的絕對值排序
l1 = [1,3,5,-2,-4,-6] l2 = sorted(l1,key=abs) print(l1) print(l2)列表按照絕對值排序
l = [[1,2],[3,4,5,6],(7,),‘123‘] print(sorted(l,key=len))列表按照每一個元素的len排序
#字符串可以提供的參數 ‘s‘ None >>> format(‘some string‘,‘s‘) ‘some string‘ >>> format(‘some string‘) ‘some string‘ #整形數值可以提供的參數有 ‘b‘ ‘c‘ ‘d‘ ‘o‘ ‘x‘ ‘X‘ ‘n‘ None >>> format(3,‘b‘) #轉換成二進制 ‘11‘ >>> format(97,‘c‘) #轉換unicode成字符 ‘a‘ >>> format(11,‘d‘) #轉換成10進制 ‘11‘ >>> format(11,‘o‘) #轉換成8進制 ‘13‘ >>> format(11,‘x‘) #轉換成16進制 小寫字母表示 ‘b‘ >>> format(11,‘X‘) #轉換成16進制 大寫字母表示 ‘B‘ >>> format(11,‘n‘) #和d一樣 ‘11‘ >>> format(11) #默認和d一樣 ‘11‘ #浮點數可以提供的參數有 ‘e‘ ‘E‘ ‘f‘ ‘F‘ ‘g‘ ‘G‘ ‘n‘ ‘%‘ None >>> format(314159267,‘e‘) #科學計數法,默認保留6位小數 ‘3.141593e+08‘ >>> format(314159267,‘0.2e‘) #科學計數法,指定保留2位小數 ‘3.14e+08‘ >>> format(314159267,‘0.2E‘) #科學計數法,指定保留2位小數,采用大寫E表示 ‘3.14E+08‘ >>> format(314159267,‘f‘) #小數點計數法,默認保留6位小數 ‘314159267.000000‘ >>> format(3.14159267000,‘f‘) #小數點計數法,默認保留6位小數 ‘3.141593‘ >>> format(3.14159267000,‘0.8f‘) #小數點計數法,指定保留8位小數 ‘3.14159267‘ >>> format(3.14159267000,‘0.10f‘) #小數點計數法,指定保留10位小數 ‘3.1415926700‘ >>> format(3.14e+1000000,‘F‘) #小數點計數法,無窮大轉換成大小字母 ‘INF‘ #g的格式化比較特殊,假設p為格式中指定的保留小數位數,先嘗試采用科學計數法格式化,得到冪指數exp,如果-4<=exp<p,則采用小數計數法,並保留p-1-exp位小數,否則按小數計數法計數,並按p-1保留小數位數 >>> format(0.00003141566,‘.1g‘) #p=1,exp=-5 ==》 -4<=exp<p不成立,按科學計數法計數,保留0位小數點 ‘3e-05‘ >>> format(0.00003141566,‘.2g‘) #p=1,exp=-5 ==》 -4<=exp<p不成立,按科學計數法計數,保留1位小數點 ‘3.1e-05‘ >>> format(0.00003141566,‘.3g‘) #p=1,exp=-5 ==》 -4<=exp<p不成立,按科學計數法計數,保留2位小數點 ‘3.14e-05‘ >>> format(0.00003141566,‘.3G‘) #p=1,exp=-5 ==》 -4<=exp<p不成立,按科學計數法計數,保留0位小數點,E使用大寫 ‘3.14E-05‘ >>> format(3.1415926777,‘.1g‘) #p=1,exp=0 ==》 -4<=exp<p成立,按小數計數法計數,保留0位小數點 ‘3‘ >>> format(3.1415926777,‘.2g‘) #p=1,exp=0 ==》 -4<=exp<p成立,按小數計數法計數,保留1位小數點 ‘3.1‘ >>> format(3.1415926777,‘.3g‘) #p=1,exp=0 ==》 -4<=exp<p成立,按小數計數法計數,保留2位小數點 ‘3.14‘ >>> format(0.00003141566,‘.1n‘) #和g相同 ‘3e-05‘ >>> format(0.00003141566,‘.3n‘) #和g相同 ‘3.14e-05‘ >>> format(0.00003141566) #和g相同 ‘3.141566e-05‘ format(了解即可)format(了解即可)
字典的運算:最小值,最大值,排序 salaries={ ‘egon‘:3000, ‘alex‘:100000000, ‘wupeiqi‘:10000, ‘yuanhao‘:2000 } 叠代字典,取得是key,因而比較的是key的最大和最小值 >>> max(salaries) ‘yuanhao‘ >>> min(salaries) ‘alex‘ 可以取values,來比較 >>> max(salaries.values()) >>> min(salaries.values()) 但通常我們都是想取出,工資最高的那個人名,即比較的是salaries的值,得到的是鍵 >>> max(salaries,key=lambda k:salary[k]) ‘alex‘ >>> min(salaries,key=lambda k:salary[k]) ‘yuanhao‘ 也可以通過zip的方式實現 salaries_and_names=zip(salaries.values(),salaries.keys()) 先比較值,值相同則比較鍵 >>> max(salaries_and_names) (100000000, ‘alex‘) salaries_and_names是叠代器,因而只能訪問一次 >>> min(salaries_and_names) Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: min() arg is an empty sequence sorted(iterable,key=None,reverse=False)!!! lambda與內置函數結合使用
五、匿名函數
匿名函數:為了解決那些功能簡單而設置的一句話函數
#這段代碼 def calc(n): return n**n print(calc(10)) #換成匿名函數 calc = lambda n:n**n print(calc(10))
上面是我們對calc這個匿名函數的分析,下面給出了一個關於匿名函數格式的說明
函數名 = lambda 參數 :返回值 #參數可以有多個,用逗號隔開 #匿名函數不管邏輯多復雜,只能寫一行,且邏輯執行結束後的內容就是返回值 #返回值和正常的函數一樣可以是任意數據類型
我們可以看出匿名函數並非真的沒有函數名,他的調用和函數的調用也就沒有區別,也是只需要 函數名(參數) 即可
上邊是匿名函數的函數用法,除此之外還可以匿名真的可以匿名,並和其他函數合作使用
l=[3,2,100,999,213,1111,31121,333] print(max(l)) dic={‘k1‘:10,‘k2‘:100,‘k3‘:30} print(max(dic)) print(dic[max(dic,key=lambda k:dic[k])])
有名函數與匿名函數的對比
#有名函數與匿名函數的對比 有名函數:循環使用,保存了名字,通過名字就可以重復引用函數功能 匿名函數:一次性使用,隨時隨時定義 應用:max,min,sorted,map,reduce,filter
課後作業
1 文件內容如下,標題為:姓名,性別,年紀,薪資
egon male 18 3000
alex male 38 30000
wupeiqi female 28 20000
yuanhao female 28 10000
要求:
從文件中取出每一條記錄放入列表中,
列表的每個元素都是{‘name‘:‘egon‘,‘sex‘:‘male‘,‘age‘:18,‘salary‘:3000}的形式
2 根據1得到的列表,取出薪資最高的人的信息。
3 根據1得到的列表,取出最年輕的人的信息。
4 根據1得到的列表,將每個人的信息中的名字映射成首字母大寫的形式。
5 根據1得到的列表,過濾掉名字以a開頭的人的信息。
6 使用遞歸打印斐波那契數列(前兩個數的和得到第三個數,如:0 1 1 2 3 4 7...)。
7 一個嵌套很多層的列表,如l=[1,2,[3,[4,5,6,[7,8,[9,10,[11,12,13,[14,15]]]]]]],用遞歸取出所有的值
#1 with open(‘db.txt‘) as f: items=(line.split() for line in f) info=[{‘name‘:name,‘sex‘:sex,‘age‘:age,‘salary‘:salary} for name,sex,age,salary in items] print(info) #2 print(max(info,key=lambda dic:dic[‘salary‘])) #3 print(min(info,key=lambda dic:dic[‘age‘])) # 4 info_new=map(lambda item:{‘name‘:item[‘name‘].capitalize(), ‘sex‘:item[‘sex‘], ‘age‘:item[‘age‘], ‘salary‘:item[‘salary‘]},info) print(list(info_new)) #5 g=filter(lambda item:item[‘name‘].startswith(‘a‘),info) print(list(g)) #6 #非遞歸 def fib(n): a,b=0,1 while a < n: print(a,end=‘ ‘) a,b=b,a+b print() fib(10) #遞歸 def fib(a,b,stop): if a > stop: return print(a,end=‘ ‘) fib(b,a+b,stop) fib(0,1,10) #7 l=[1,2,[3,[4,5,6,[7,8,[9,10,[11,12,13,[14,15]]]]]]] def get(seq): for item in seq: if type(item) is list: get(item) else: print(item) get(l)答案
三元表達式、列表推導式、生成器表達式、遞歸、內置函數、匿名函數