一 集合
1 集合定義:
1 如果花括號為空,則是字典類型
2 定義一個空集合,使用set 加小括號
使用B方式定義集合時,集合內部的數必須是可迭代對象,數值類型的不可以
其中的值必須是可迭代對象,其中的元素必須是可hash,其中s=set([1,2,3,4,5,6]) 的含義是其是列表,其列表是可迭代,且其獲取到的是其中的元素,不是列表。
2 set 和線性結構
線性結構的查詢時間復雜度是O(n),即隨著數據規模的增大而增加耗時
set、dict 等結構,內部使用hash值做為key,時間復雜度可以做到O(1),查詢時間和數據規模無關
可hash的對象
數值類型 int float complex
布爾型 True False
字符串 string bytes
tuple
None
以上都是不可變類型,稱為可哈西類型,hashable
set 的元素必須是可hash的。
2 集合的簡單應用
實現對集合內元素的去重操作,此操作可應用于對列表的去重
1 使用集合對列表進行去重操作
2 使用字典的鍵不重復性對列表進行去重
3集合的增刪改查
1 集合的增:
A add 實現對非可變類型數據的添加操作(除列表,字典)
B update 實現對可迭代對象的加入操作(數值類型則不能加入其中)
2 刪
A pop()支持對集合的無序刪除操作
B remove 支持對集合的指定元素的刪除工作,若不存在,則報錯
C discard 刪除集合中指定元素,如果不存在,則無反應
D clear 清空集合
例題應用:
要求輸入一個數,使其成為1-1000之間產生隨機數的個數的總和個數,并對這些數進行排序(有小到大)
1
[root@www ~]# cat a.py
#!/usr/bin/env python
#coding=utf-8
import random #導入該模塊,用于生成1到1000的隨機數
l1=[]
s=set()
N=input("請輸入數字總和N:")
for i in range(N): #進行循環的總數N1=random.randint(1,1000) # 生成1-1000內的隨機數N個 s.add(N1)l1=list(s)l1.sort() #使用列表的內置方法進行排序
print l1
2
[root@www ~]# cat a.py
#!/usr/bin/env python
#coding=utf-8
import random
l1=[]
s=set()
N=input("請輸入數字總和N:")
for i in range(N):N1=random.randint(1,1000)s.add(N1)l1=list(s)
print sorted(l1) 使用內置函數進行排序
3 查(關系測試)
1 交集 (輸出兩個集合中共有的元素)
2 并集(輸出列個集合中所有存在的元素)
3 差集(輸出第一個集合中與第二個集合不同的元素)
4 對等差分 (輸出兩個集合中各不存在但對方存在的元素)
集合關系判斷(子集,父集)
4 練習
隨機產生2個各10個數字的列表,要求如下:
1 每個數字取值范圍是[10,20]
2 統計20個數字中,一共多少個不同的數字
3 2組中,不重復的數字有幾個,分別是多少
4 2 組中,重復的數字有幾個,分別是什么
import random
l1=[]
l2=[]
for i in range(10): # 生成10個隨機數,其取值范圍是10,20l1.append(random.randint(10,20))l2.append(random.randint(10,20))print ("不同數字個數為{},不重復數字有{}個,分別是{},重復數字為{},共{}個".format(set(set(l1)|set(l2)),(len(set(l1)^set(l2))),(set(l1)^set(l2)),(set(l1)&set(l2)),len(set(l1)&set(l2))))# 不重復表示是對等差集
二 總結:
1 可變數據類型:列表,字典,集合
2 不可變數據類型:數值類型,元祖,字符串可變數據類型實現某個功能,直接改變可變的數據
不可變數據類型實現某些功能,需要將結果賦值給另一個變量可迭代數據類型(能實現for 循環):str list tuple dict set
不可迭代數據類型:數值類型是否支持索引,切片,鏈接,重復特性
有序的數據類型:str list tuple
無序的數據類型:dict set
二 解析式
1 列表解析 list comprehension
1 概述
列表解析式是一種語法糖
編譯器會優化,不會因為簡寫而影響效率,反而因優化而提高了效率
減少程序員工作量,減少出錯
簡化了代碼,但可讀性增強
2 語法
語法:
[ 返回值 for 元素 in 可迭代對象 if 條件]
使用中括號[],內部是for循環,if 條件語句可選
返回一個新的列表
3 進階
[item for item in iterable if cond1 if cond2] #等價于ret=[]
for item in iterable:if cond1:if cond2:ret.append(item)[ (i*j) for i in iterable1 for j in iterable2] #等價于
ret=[]
for i in iterable1:for j in iterable2:ret.append(i*j)
4 練習
1 返回1-10平方的列表
In [1]: [pow(i,2) for i in range(1,11)]
Out[1]: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
2 有一個列表lst=[1,4,9,16,2,5,10,15],生成一個新列表,要求新列表的元素是lst相鄰2項的和
In [15]: lst=[1,4,9,16,2,5,10,15]
In [16]: [lst[i]+lst[i+1] for i in range(len(lst)-1)]
Out[16]: [5, 13, 25, 18, 7, 15, 25]
3 打印九九乘法表
In [5]: [print ("{}*{}={:<3}{}".format(j,i,j*i,'\n' if i==j else " "),end="") for i...: in range(1,10) for j in range(1,i+1)]
1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
1*4=4 2*4=8 3*4=12 4*4=16
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81
4 "0001.abcdefghij" 是ID格式,要求ID格式是以點好分割,左邊是4位從1開始的整數,右邊是10位隨機小寫英文字母,請以此生成前100個id的列表。
In [1]: import random In [2]: import string In [3]: ["{:04}.{}".format(i,"".join(random.sample(string.ascii_lowercase,10))) for i...: in range(1,101)]
Out[3]:
['0001.wzmedfgach','0002.teandiuzbq','0003.mgvprdwtbz','0004.hdcjryliun','0005.rkbdanezip','0006.yabquwrjfm','0007.xhriugvyfl','0008.yjosmvrxuf','0009.oepwvfyzxj','0010.hzcigsnqkw','0011.kygrvidtla','0012.tpsjmzdvca','0013.mhwixqprdy','0014.rmgvxubklj','0015.crtwsnpubg','0016.tpcmeoxgzf','0017.ulovngcyki','0018.njiagycwvd','0019.sbjcutgvxr','0020.cazqujrdtk','0021.fnteuvaozd','0022.zlsiqxwcoa','0023.lxzojifvqb','0024.zpudanijfm','0025.zdjsawlurp','0026.viqekcsfyr','0027.psgitcvwlq','0028.xnwyjvstdp','0029.jdnbazgrxo','0030.ifshwdnmpy','0031.dfchqxuvbj','0032.jdkehycosl','0033.bjhnofwxgd','0034.kbucwogptl','0035.ctosfdqaie','0036.plcgqbvnzr','0037.lbygqswtjo','0038.clgqzrmfpe','0039.xynsopwfld','0040.lzqxkeycjg','0041.azexdhpwqf','0042.sqxubrijdo','0043.xrdbtspiac','0044.unvjbchdsi','0045.xwfrtduobv','0046.fmjgwnahyz','0047.qjcvluokpw','0048.depfjnyviw','0049.fyhvctzneb','0050.grblkwfioq','0051.mvlfdaengp','0052.bxlnkfuoqh','0053.kicejmfqxn','0054.qxzpjolvkw','0055.sptuwycjrx','0056.bhljztgdfi','0057.htrjiqxfdv','0058.hfqdnurxbp','0059.kygirhzjbe','0060.gkilhandxs','0061.okbmcgzqwv','0062.lkujswvyra','0063.jeqvbuczap','0064.asqfmkrjpn','0065.tdaufvkrie','0066.axlgjumfbe','0067.kgwvhlodrt','0068.psvwahceiz','0069.srtufplwaj','0070.lvhouijnxw','0071.ofkmaiugqc','0072.awfpcyogie','0073.agckzpbxyf','0074.zpmsajbxld','0075.jskbpqzxcv','0076.cgevhqjkfr','0077.uwirenmlhk','0078.gnbozqvmif','0079.hbjtcrpxds','0080.qkvwluazfm','0081.dileuwsmfh','0082.djmgswhytp','0083.pictkgmefh','0084.aqijzmpkny','0085.bwmgudzclt','0086.omzwylnbxp','0087.nhvgfbrdyq','0088.sdaiwoqzht','0089.xiqetyjprf','0090.qaidkozlmg','0091.xwarkuylfo','0092.dqmkpobfia','0093.owqausrpnb','0094.gxazkslifh','0095.dtxfepmylv','0096.olejwvhsfp','0097.excdapiyvb','0098.zoq***ytbu','0099.euhjblfqkn','0100.pzhejmwybg']
2 集合解析式
1 語法
{ 返回值 for 元素 In 可迭代對象 if 條件}立即返回一個集合
2 練習
返回一個1到10的平方的集合
In [1]: {pow(i,2) for i in range(1,11)}
Out[1]: {1, 4, 9, 16, 25, 36, 49, 64, 81, 100}
3 字典解析式
1 語法
{返回值 for 元素 In 可迭代對象 if 條件 }
使用key,value 形式接受
立即返回一個字典
2 練習
In [2]: {str(i):i for i in range(10)}
Out[2]:
{'0': 0,'1': 1,'2': 2,'3': 3,'4': 4,'5': 5,'6': 6,'7': 7,'8': 8,'9': 9}In [3]: {str(i):[i,i+1] for i in range(10)}
Out[3]:
{'0': [0, 1],'1': [1, 2],'2': [2, 3],'3': [3, 4],'4': [4, 5],'5': [5, 6],'6': [6, 7],'7': [7, 8],'8': [8, 9],'9': [9, 10]}In [4]: {str(i):[j] for i in range(10) for j in range(10,21)} # 此處會覆蓋,因為前面一直在賦值。
Out[4]:
{'0': [20],'1': [20],'2': [20],'3': [20],'4': [20],'5': [20],'6': [20],'7': [20],'8': [20],'9': [20]}
三 生成器表達式
1 和列表解析式的區別
生成器表達式是按需計算(或成為惰性求值,延遲計算),需要的時候才計算值
列表解析式是立即返回值,生成器從前到后走完一遍后,不能回頭。列表解析從簽到后走完一邊后可以回頭迭代。
生成器 是可迭代對象,是迭代器
迭代器只能使用一次,但可迭代對象不能使用next()方法
能用next,必須是迭代器,
可迭代對象不一定是迭代器,但迭代器一定是可迭代對象
2 語法
(返回值 for 元素 in 可迭代對象 if 條件)
列表解析式中括號換成了小括號
返回一個生成器
3 練習
由上述可知,生成器只能迭代一次,而列表解析式可以重復迭代
In [6]: it=("{}".format(i+1) for i in range(2)) In [7]: next(it)
Out[7]: '1'In [8]: next(it)
Out[8]: '2'In [10]: it=("{}".format(i+1) for i in range(2)) In [11]: for i in it: ...: print (i) ...:
1
2
四 函數
1 無參數的函數
函數的定義:
def 函數名():
函數體函數的調用:
函數名()定義函數時,函數不執行,調用函數時,函數才執行
2 有參數的函數
1 形參
在def 函數定義時使用的參數稱為形式參數,不具備實際的意義,
def a1(x,y):
....: print x+y此時的x,y被稱為形式參數
形參的分類A 必須參數
def a1(x,y):
....: print x+y
B 默認參數
In [59]: def a4(x,y=1): #y=1 用于當只傳入一個參數時,此y=1則會發生作用,若傳入兩個參數,則失效
....: print x,y
....:In [60]: a4(1)
1 1In [61]: a4(1,2)
1 2
C 可變參數
In [38]: def a2(*x): 可以同時傳輸多個參數,其產生的結果是一個元祖
....: print x
....:In [39]: a2(1,2,3,4,5,6)
(1, 2, 3, 4, 5, 6)a2([1,2,3,4,5])
([1, 2, 3, 4, 5],)
D 關鍵字參數:
In [57]: def a3(**x):
....: print x #其返回值是一個字典
....:In [58]: a3(a=1,b=2,c=3)
{'a': 1, 'c': 3, 'b': 2}函數定義時,若有多種類型的參數需要定義,則必須要遵循:必須參數--默認參數--可變參數--關鍵字參數
2 實參
在調用函數時傳入函數體內部的參數稱為實參,有實際的效果的參數
In [35]: a1(1,2)
3
In [36]: a=1;b=3
In [37]: a1(a,b)
4
此時的1,2 和 a,b 都是實參
應用,用于數之和
In [41]: def a2(*x):
....: sum=0
....: for i in x:
....: sum+=i
....: print sum
....:
In [42]: a2(1,2,3,4,5,6,7,8,9)
45
3返回值
函數中沒有return時,默認返回None
1 返回多個值
#!/usr/bin/env python
#coding=utf-8
def a1(\*args):'''
返回最大值和最小值
:param args: 要求輸入多個數作比較
:return: 返回最大值和最小值'''
return max(args) ,min(args)
print a1(1,2,3,4,10,20,100)
4 函數的變量作用域
作用域 : 一個標識符的可見范圍,這就是標識符的作用域,一般常說的是變量的作用域。
全局作用域:
在整個程序運行環境中均可見局部作用域:
在函數/類等內部可見
局部變量使用范圍不能超過其所在的局部作用域
In [1]: def x(): ...: a=1 ...: In [2]: def y(): ...: print (a) ...: In [3]: print (a) #在函數x中定義的局部變量在外部不能調用 NameError Traceback (most recent call last)
<ipython-input-3-cb9bacd097d9> in <module>
----> 1 print (a)NameError: name 'a' is not definedIn [4]: y() # 在函數x中定義的局部變量在函數y中不能被調用
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-4-6fa9c8f97a35> in <module>
----> 1 y()<ipython-input-2-455e1fcd2512> in y()1 def y():
----> 2 print (a)3 NameError: name 'a' is not defined
重點
In [1]: x=5 In [2]: def a(): ...: y= x+1 ...: print (x) ...: In [3]: a()
5In [4]: def b(): ...: x=x+1 ...: print (x) ...: In [5]: b
Out[5]: <function __main__.b()>In [6]: b()
---------------------------------------------------------------------------
UnboundLocalError Traceback (most recent call last)
<ipython-input-6-3bf86fc5afda> in <module>
----> 1 b()<ipython-input-4-b0b3ab5ae26b> in b()1 def b():
----> 2 x=x+13 print (x)4 UnboundLocalError: local variable 'x' referenced before assignment
x+=1 可以轉換為x=x+1, x= 相當于定義了新的變量x,其相當于賦值前引用變量。一般是先賦值,后引用。
解決方式
1 定義全局變量
x=5
In [7]: def b(): ...: global x # 全局變量中必須要有,否則出錯...: x=x+1 ...: print (x) ...: In [8]: b()
6
In [1]: x=5 In [2]: def a(): ...: global x ...: x=10 ...: x+=1 ...: print (x) ...: In [3]: a()
11In [4]: print (x)
11
此時內部的x=10相當于覆蓋了外部的x=5,因此其值會變成此種情況
global 關鍵字必須要先聲明,再使用
#!/usr/bin/env python
#coding=utf-8x=1
def a1(x):x=2print x
print x 其結果是x=1
a1(x) 其結果是x=2 ,因為在調用函數內部時,此x=2是局部變量,其優先級高于x=1
global總結:
x+=1 這中特殊形式產生的原因是先引用后賦值,而python中動態語言是賦值之后才有意義,才能被引用,解決方式有兩種,第一種是直接在內部定義覆蓋外部,第二種是使用global 進行聲明,讓其去外部尋找該變量然后完成運算,
內部作用域賦值全局作用域的變量,其會覆蓋全局變量在本函數內的變量值,而使用global 聲明其為全局的,一旦內部進行重新賦值,則該值成為全局變量的值。
global使用規則:
1 外部作用域變量會在內部作用域可見,但也不要在這個內部的局部作用域中直接使用,因為函數的目的就是封裝,而應該盡量與外界隔離。
2 如果函數需要使用外部全局變量,則建議使用形參傳遞參數解決,盡量不適用定義。
3 不建議使用global
5 默認值作用域
1 實例
實例1
In [1]: def a(x=1): ...: print (x) ...: In [2]: a()
1In [3]: a()
1In [4]: print (x)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-4-606ad02f996c> in <module>
----> 1 print (x)NameError: name 'x' is not defined
此處因為x是局部變量,及默認形式參數是局部變量
實例2
In [1]: def a(x=[]): ...: x.append(1) ...: print (x) ...: In [2]: a()
[1]In [3]: a()
[1, 1]In [4]: a()
[1, 1, 1]
上述實例中,原本的結果應該是每次調用其值都是一個列表,因為函數在調用完成后便會自動消失,但次上述出問題的原因是其默認作用域的原因,因為函數也是對象,python將函數的默認值放置在了屬性中,這個屬性就伴隨著函數對象的整個生命周期,a.defaults表示了函數對象的屬性,及保存其默認屬性值的位置,
實例3
In [1]: def a(x=[],y=1,z=2): ...: x.append(1) ...: print (x) ...: In [2]: print (a(),id(a))
[1]
None 139758163502216In [3]: print (a.__defaults__)
([1], 1, 2)In [4]: print (a(),id(a))
[1, 1]
None 139758163502216In [5]: print (a.__defaults__)
([1, 1], 1, 2)
上述結果可得,其函數的地址沒變,及函數對象沒變,調用屬性defaults使用元祖保存其default默認值,但元祖中有列表,其元祖中的列表是可變的,因此其會發生變化
實例4
In [1]: def a(x,y=1,z=2): ...: y=2 ...: z=3 ...: print (x,y,z) ...: In [2]: print (a.__defaults__)
(1, 2)In [3]: a(10)
10 2 3In [4]: print (a.__defaults__)
(1, 2)
由此可知: 可變類型默認值,如果使用默認值,則就可能修改這個默認值,某些時候是不需要的,解決方式如下:
1 影子拷貝
In [1]: def a(x=[],y=1,z=2): ...: print (id(x)) ...: x=x[:] #使用影子拷貝,其返回的是一個全新的列表,和切片一樣,其比較浪費內存資源。...: print (id(x)) ...: x.append(1) ...: print (x) ...: In [2]: a()
140285447782088
140285501277768
[1]In [3]: print (a.__defaults__)
([], 1, 2)In [4]: a([10])
140285501944072
140285481599304
[10, 1]In [5]: print (a.__defaults__)
([], 1, 2)In [6]: a([10,20])
140285447692488
140285447654920
[10, 20, 1]In [7]: print (a.__defaults__)
([], 1, 2)
2 使用不可變類型進行處理
In [1]: def a(x=None,y=1,z=2): ...: if x is None: ...: x=[] ...: x.append(1) ...: print (x) ...: In [2]: a()
[1]In [3]: a()
[1]In [4]: a.__defaults__
Out[4]: (None, 1, 2)In [5]: a([10]) # 此處只能傳入列表
[10, 1]In [6]: a.__defaults__
Out[6]: (None, 1, 2)
如果是傳入一個缺省值則創建一個列表,如果傳入一個列表,則修改此列表,此種方式常用,此是在原有列表的基礎上修改,較影子拷貝相比更加節省資源。
6 函數銷毀
1 全局函數銷毀
重新定義同名函數
def foo(xyz=[],u='abc',z=123):xyz.append(1)return xyz
print (foo(),id(foo),foo.__defaults__)def foo(xyz=[]): # 當第二個定義后,第一個函數將會漂浮在哪里沒人用了,直到垃圾回收器對其進行相關的回收xyz.append(1)return xyz
print (foo(),id(foo),foo.__defaults__)
結果如下
Del 語句刪除函數對象
def foo(xyz=[],u='abc',z=123):xyz.append(1)return xyz
print (foo(),id(foo),foo.__defaults__)
del foo # 使用del刪除函數的地址引用,當其地址引用為0時,其會被垃圾回收器回收
print (foo(),id(foo),foo.__defaults__)
結果如下
程序結束時
2局部函數銷毀
重新在上級作用域中定義同名函數
def foo(xyz=[],u='abc',z=123):xyz.append(1)def foo1():passprint (id(foo1))def foo1(u='acd'): # 重新定義嵌套函數print (xyz)print (id(foo1))return foo1bar=foo()
print (id(bar),foo.__defaults__) # 其中id(bar)指的是foo1的函數內存位置,其默認使用下面的函數
結果如下:
del 語句刪除函數對象
def foo(xyz=[],u='abc',z=123):xyz.append(1)def foo1():passprint (id(foo1))return foo1
bar=foo()
print (id(bar),foo.__defaults__) # 其中id(bar)指的是foo1的函數內存位置
del bar prnt (id(bar),foo.__defaults__)
結果如下
上級作用域銷毀時
7 遞歸函數
1 函數執行流程
def foo(b,b1=3):print ("foo called",b,b1)def foo1(c):foo2(c)print ("foo1 called",c)def foo2(d):print ("foo2 called",d)def main():print ("main called") # 進入上述LEGB進行尋找,最后找到build-in后調用print 返回上述結果,其會將字面常量壓到棧中,# 內存中是分堆和棧的,棧是函數的,是一個先進后出的,后進先出的,main函數的棧直接被壓在了main之上,當print執行后# 其將被彈出,彈出后,main函數中的其他內容將會被繼續執行foo(100,101) #python中沒有常量,但其有字面常量,只要敢定義,就敢變。將foo進行壓棧,將常量依次壓棧,若有變量,則進行#load,調用函數foo,創建棧幀,為此函數在棧中創建一段(棧幀),print壓棧,然后調用,后彈出。foo1(200) #下面同上print ("main ending")
main()
2 遞歸 recursion
函數直接或間接調用自身就是遞歸
遞歸需要有邊界條件,遞歸前進段,遞歸返回段
遞歸一定要有邊界條件
當邊界條件不滿足時,遞歸前進
當邊界條件滿足時,遞歸返回
實例 :
1 斐波那契數列
def x(a):if a<2:return aelse:return x(a-1)+x(a-2) # 下一個數等于前兩個之和for i in range(1,10): #通過for不斷生成下一個數print (x(i))
結果如下
2 階乘
def x(a):if a==1:return aelse:return a*x(a-1)x(10)
結果如下
3 將一個數逆序放入列表中
1234 -> [4,3,2,1]
核心思想,使用數字的處理方式將其每一位截取出來,然后進行相關的操作即可。
def x(n,l1=[]):if n<10:l1.append(n)return l1 # 最終返回值else:l1.append(n%10)return x(n//10,l1) #調用函數遞歸
print (x(1234))
結果如下
4 字典的扁平化
def d1(c1,c2=dict(),k=""): # 此處定義的空字典用于接受字典,此處的k用于接受字典的鍵(key)if type(c1)==dict:for i,j in c1.items(): # 通過此處判斷字典的值,若其值為字典類型,則繼續進行遞歸操作,直到其值不為字典時為止,if type(j)==dict:d1(j,c2,k+i)#此處的k+i及就是對兩個字符串進行組合,而后通過點號將其分離else:c2[".".join(k+i)]=jreturn c2
print (d1({'a': {'b': 1, 'c':{'i':10}}, 'd': {'e': 3, 'f': {'g':{'h':5}}}}))
結果如下
8 總結
名稱空間:一個變量所能夠生效的作用域
本地作用域:只能在函數內部使用
模塊定義:全局作用域
函數定義:本地作用域
變量名解析:LEGB 原則:
變量名引用分三個作用域進行: 首先是本地。之后是函數內,接著是全局,最后是內置
Python 創建、改變或查找變量名都是在名稱空間中進行
在代碼中變量名被賦值的位置決定了其能被訪問到的返回
函數定義了本地作用域,而模塊定義了全局作用域
每個模塊都是一個全局作用域,因此,全局作用域的范圍僅限于單個程序文件
每次對函數的調用都會創建一個人新的本地作用域,賦值的變量除非聲明為全局變量,否則均為本地變量
所有的變量都可以歸納為本地、全局或內置的(由_builtin_模塊所提供的)
轉載于:https://blog.51cto.com/11233559/2059485