1 模塊初識
- Python的強大之處在於他有非常豐富和強大的標准庫和第三方庫,幾乎你想實現的任何功能都有相應的Python庫支持,以后的課程中會深入講解常用到的各種庫,現在,我們先來象征性的學2個簡單的。
sys模塊
import sys
print(sys.argv)
輸出結果
['D:/python project/基礎課程/Day2_2016-7-30/博客測試專用.py']-
打印出這個Python文件的路徑
os模塊
import os
os.system("df -h") #調用系統命令
os模塊可以調用Linux命令
2 .pyc是個什么鬼?
2.1 Python是一門解釋型語言?
我初學Python時,聽到的關於Python的第一句話就是,Python是一門解釋性語言,我就這樣一直相信下去,直到發現了.pyc文件的存在。如果是解釋型語言,那么生成的.pyc文件是什么呢?c應該是compiled的縮寫才對啊!
為了防止其他學習Python的人也被這句話誤解,那么我們就在文中來澄清下這個問題,並且把一些基礎概念給理清。
2.2 解釋型語言和編譯型語言
計算機是不能夠識別高級語言的,所以當我們運行一個高級語言程序的時候,就需要一個“翻譯機”來從事把高級語言轉變成計算機能讀懂的機器語言的過程。這個過程分成兩類,第一種是編譯,第二種是解釋。
編譯型語言在程序執行之前,先會通過編譯器對程序執行一個編譯的過程,把程序轉變成機器語言。運行時就不需要翻譯,而直接執行就可以了。最典型的例子就是C語言。
解釋型語言就沒有這個編譯的過程,而是在程序運行的時候,通過解釋器對程序逐行作出解釋,然后直接運行,最典型的例子是Ruby。
通過以上的例子,我們可以來總結一下解釋型語言和編譯型語言的優缺點,因為編譯型語言在程序運行之前就已經對程序做出了“翻譯”,所以在運行時就少掉了“翻譯”的過程,所以效率比較高。但是我們也不能一概而論,一些解釋型語言也可以通過解釋器的優化來在對程序做出翻譯時對整個程序做出優化,從而在效率上超過編譯型語言。
此外,隨着Java等基於虛擬機的語言的興起,我們又不能把語言純粹地分成解釋型和編譯型這兩種。
用Java來舉例,Java首先是通過編譯器編譯成字節碼文件,然后在運行時通過解釋器給解釋成機器文件。所以我們說Java是一種先編譯后解釋的語言。
2.3 Python到底是什么
其實Python和Java/C#一樣,也是一門基於虛擬機的語言,我們先來從表面上簡單地了解一下Python程序的運行過程吧。
當我們在命令行中輸入python hello.py時,其實是激活了Python的“解釋器”,告訴“解釋器”:你要開始工作了。可是在“解釋”之前,其實執行的第一項工作和Java一樣,是編譯。
熟悉Java的同學可以想一下我們在命令行中如何執行一個Java的程序:
javac hello.java
java hello
只是我們在用Eclipse之類的IDE時,將這兩部給融合成了一部而已。其實Python也一樣,當我們執行python hello.py時,他也一樣執行了這么一個過程,所以我們應該這樣來描述Python,Python是一門先編譯后解釋的語言。
2.4 簡述Python的運行過程
在說這個問題之前,我們先來說兩個概念,PyCodeObject和pyc文件。
我們在硬盤上看到的pyc自然不必多說,而其實PyCodeObject則是Python編譯器真正編譯成的結果。我們先簡單知道就可以了,繼續向下看。
當python程序運行時,編譯的結果則是保存在位於內存中的PyCodeObject中,當Python程序運行結束時,Python解釋器則將PyCodeObject寫回到pyc文件中。
當python程序第二次運行時,首先程序會在硬盤中尋找pyc文件,如果找到,則直接載入,否則就重復上面的過程。
所以我們應該這樣來定位PyCodeObject和pyc文件,我們說pyc文件其實是PyCodeObject的一種持久化保存方式。
3 數據類型初識
3.1 數字
2 是一個整數的例子。
長整數 不過是大一些的整數。
3.23和52.3E-4是浮點數的例子。E標記表示10的冪。在這里,52.3E-4表示52.3 * 10-4。
(-5+4j)和(2.3-4.6j)是復數的例子,其中-5,4為實數,j為虛數,數學中表示復數是什么?。
int(整型)
在32位機器上,整數的位數為32位,取值范圍為-231~231-1,即-2147483648~ 2147483647
在64位系統上,整數的位數為64位,取值范圍為-263~263-1,即-9223372036854775808~9223372036854775807
long(長整型)
跟C語言不同,Python的長整數沒有指定位寬,即:Python沒有限制長整數數值的大小,但實際上由於機器內存有限,我們使用的長整數數值不可能無限大。
注意,自從Python2.2起,如果整數發生溢出,Python會自動將整數數據轉換為長整數,所以如今在長整數數據后面不加字母L也不會導致嚴重后果了。
float(浮點型)
浮點數用來處理實數,即帶有小數的數字。類似於C語言中的double類型,占8個字節(64位),其中52位表示底,11位表示指數,剩下的一位表示符號。
complex(復數)
復數由實數部分和虛數部分組成,一般形式為x+yj,其中的x是復數的實數部分,y是復數的虛數部分,這里的x和y都是實數。
注:Python中存在小數字池:-5 ~ 257
3.2 布爾值
真或假
1 或 0
4 字符串
"hello world"
萬惡的字符串拼接:
python中的字符串在C語言中體現為是一個字符數組,每次創建字符串時候需要在內存中開辟一塊連續的空,並且一旦需要修改字符串的話,就需要再次開辟空間,萬惡的+號每出現一次就會在內從中重新開辟一塊空間。
name = "wu"
print("i am %s" % name)
字符串是----%s 整數------- %d; 浮點數-----%f
4.1 字符串中字符大小寫的變換:
S.lower() #小寫
S.upper() #大寫
S.swapcase() #大小寫互換
S.capitalize() #首字母大寫
String.capwords(S)
#這是模塊中的方法。它把S用split()函數分開,然后用capitalize()把首字母變成大寫,最后用join()合並到一起
S.title() #只有首字母大寫,其余為小寫,模塊中沒有這個方法
字符串在輸出時的對齊:
S.ljust(width,[fillchar])
#輸出width個字符,S左對齊,不足部分用fillchar填充,默認的為空格。
S.rjust(width,[fillchar]) #右對齊
S.center(width, [fillchar]) #中間對齊
S.zfill(width) #把S變成width長,並在右對齊,不足部分用0補足
字符串中的搜索和替換:
S.find(substr, [start, [end]])
#返回S中出現substr的第一個字母的標號,如果S中沒有substr則返回-1。start和end作用就相當於在S[start:end]中搜索
S.index(substr, [start, [end]])
#與find()相同,只是在S中沒有substr時,會返回一個運行時錯誤
S.rfind(substr, [start, [end]])
#返回S中最后出現的substr的第一個字母的標號,如果S中沒有substr則返回-1,也就是說從右邊算起的第一次出現的substr的首字母標號
S.rindex(substr, [start, [end]])
S.count(substr, [start, [end]]) #計算substr在S中出現的次數
S.replace(oldstr, newstr, [count])
#把S中的oldstar替換為newstr,count為替換次數。這是替換的通用形式,還有一些函數進行特殊字符的替換
S.strip([chars])
#把S中前后chars中有的字符全部去掉,可以理解為把S前后chars替換為None
S.lstrip([chars])
S.rstrip([chars])
S.expandtabs([tabsize])
#把S中的tab字符替換沒空格,每個tab替換為tabsize個空格,默認是8個
字符串的分割和組合:
S.split([sep, [maxsplit]])
#以sep為分隔符,把S分成一個list。maxsplit表示分割的次數。默認的分割符為空白字符
S.rsplit([sep, [maxsplit]])
S.splitlines([keepends])
#把S按照行分割符分為一個list,keepends是一個bool值,如果為真每行后而會保留行分割符。
S.join(seq) #把seq代表的序列──字符串序列,用S連接起來
字符串的mapping,這一功能包含兩個函數:
String.maketrans(from, to)
#返回一個256個字符組成的翻譯表,其中from中的字符被一一對應地轉換成to,所以from和to必須是等長的。
S.translate(table[,deletechars])
# 使用上面的函數產后的翻譯表,把S進行翻譯,並把deletechars中有的字符刪掉。需要注意的是,如果S為unicode字符串,那么就不支持 deletechars參數,可以使用把某個字符翻譯為None的方式實現相同的功能。此外還可以使用codecs模塊的功能來創建更加功能強大的翻譯表。
字符串還有一對編碼和解碼的函數:
S.encode([encoding,[errors]])
# 其中encoding可以有多種值,比如gb2312 gbk gb18030 bz2 zlib big5 bzse64等都支持。errors默認值為"strict",意思是UnicodeError。可能的值還有'ignore', 'replace', 'xmlcharrefreplace', 'backslashreplace' 和所有的通過codecs.register_error注冊的值。這一部分內容涉及codecs模塊,不是特明白
S.decode([encoding,[errors]])
字符串的測試函數,這一類函數在string模塊中沒有,這些函數返回的都是bool值:
S.startwith(prefix[,start[,end]])
#是否以prefix開頭
S.endwith(suffix[,start[,end]])
#以suffix結尾
S.isalnum()
#是否全是字母和數字,並至少有一個字符
S.isalpha() #是否全是字母,並至少有一個字符
S.isdigit() #是否全是數字,並至少有一個字符
S.isspace() #是否全是空白字符,並至少有一個字符
S.islower() #S中的字母是否全是小寫
S.isupper() #S中的字母是否便是大寫
S.istitle() #S是否是首字母大寫的
字符串類型轉換函數,這幾個函數只在string模塊中有:
string.atoi(s[,base])
#base默認為10,如果為0,那么s就可以是012或0x23這種形式的字符串,如果是16那么s就只能是0x23或0X12這種形式的字符串
string.atol(s[,base]) #轉成long
string.atof(s[,base]) #轉成float
這里再強調一次,字符串對象是不可改變的,也就是說在python創建一個字符串后,你不能把這個字符中的某一部分改變。任何上面的函數改變了字符串后,都會返回一個新的字符串,原字串並沒有變。其實這也是有變通的辦法的,可以用S=list(S)這個函數把S變為由單個字符為成員的list,這樣的話就可以使用S[3]='a'的方式改變值,然后再使用S=" ".join(S)還原成字符串
5 列表
創建列表
sample_list = ['a',1,('a','b')]
Python 列表操作
sample_list = ['a','b',0,1,3]
得到列表中的某一個值
value_start = sample_list[0]
end_value = sample_list[-1]
刪除列表的第一個值
del sample_list[0]
在列表中插入一個值
sample_list[0:0] = ['sample value']
得到列表的長度
list_length = len(sample_list)
列表遍歷
for element in sample_list:
print(element)
Python 列表高級操作/技巧
產生一個數值遞增列表
num_inc_list = range(30)
#will return a list [0,1,2,...,29]
用某個固定值初始化列表
initial_value = 0
list_length = 5
sample_list = [ initial_value for i in range(10)]
sample_list = [initial_value]*list_length
# sample_list ==[0,0,0,0,0]
附:python內置類型
1、list:列表(即動態數組,C++標准庫的vector,但可含不同類型的元素於一個list中)
a = ["I","you","he","she"] #元素可為任何類型。
下標:按下標讀寫,就當作數組處理
以0開始,有負下標的使用
0第一個元素,-1最后一個元素,
-len第一個元 素,len-1最后一個元素
取list的元素數量
len(list) #list的長度。實際該方法是調用了此對象的__len__(self)方法。
創建連續的list
L = range(1,5) #即 L=[1,2,3,4],不含最后一個元素
L = range(1, 10, 2) #即 L=[1, 3, 5, 7, 9]
list的方法
L.append(var) #追加元素
L.insert(index,var)
L.pop(var) #返回最后一個元素,並從list中刪除之
L.remove(var) #刪除第一次出現的該元素
L.count(var) #該元素在列表中出現的個數
L.index(var) #該元素的位置,無則拋異常
L.extend(list) #追加list,即合並list到L上
L.sort() #排序
L.reverse() #倒序
list 操作符:,+,*,關鍵字del
a[1:] #片段操作符,用於子list的提取
[1,2]+[3,4] #為[1,2,3,4]。同extend()
[2]*4 #為[2,2,2,2]
del L[1] #刪除指定下標的元素
del L[1:3] #刪除指定下標范圍的元素
list的復制
L1 = L #L1為L的別名,用C來說就是指針地址相同,對L1操作即對L操作。函數參數就是這樣傳遞的
L1 = L[:] #L1為L的克隆,即另一個拷貝。
6 字典
dict = {'ob1':'computer', 'ob2':'mouse', 'ob3':'printer'}
每一個元素是pair,包含key、value兩部分。key是Integer或string類型,value 是任意類型。
鍵是唯一的,字典只認最后一個賦的鍵值。
dictionary的方法
D.get(key, 0) #同dict[key],多了個沒有則返回缺省值,0。[]沒有則拋異常
D.has_key(key) #有該鍵返回TRUE,否則FALSE
D.keys() #返回字典鍵的列表
D.values()
D.items()
D.update(dict2) #增加合並字典
D.popitem() #得到一個pair,並從字典中刪除它。已空則拋異常
D.clear() #清空字典,同del dict
D.copy() #拷貝字典
D.cmp(dict1,dict2) #比較字典,(優先級為元素個數、鍵大小、鍵值大小)
#第一個大返回1,小返回-1,一樣返回0
dictionary的復制
dict1 = dict #別名
dict2=dict.copy() #克隆,即另一個拷貝。
7 元組
tuple
- 元組是以圓括號“()”包圍的數據集合,不同成員以“,”分隔。通過下標進行訪問
- 不可變序列,可以看做不可變的列表,與列表不同:元組中數據一旦確立就不能改變(所以沒有類似列表的增刪改操作,只有基本序列操作)
- 支持任意類型,任意嵌套以及常見的序列操作
- 元組通常用在使語句或用戶定義的函數能夠安全地采用一組值的時候,即被使用的元組的值不會改變聲明及使用
7.1 創建元組
tup1 = ('physics', 'chemistry', 1997, 2000);
tup2 = (1, 2, 3, 4, 5 );
tup3 = "a", "b", "c", "d";
tup4 = ();#創建空元祖
tup5 = (50,);#元組中只包含一個元素時,需要在元素后面添加逗號來消除歧義。
元組和字符串類似,下標索引從0開始,可以進行截取組合等。
7.2 訪問元組
元組可以使用下標索引來訪問元組中的值。
tup1 = ('physics', 'chemistry', 1997, 2000);
tup2 = (1, 2, 3, 4, 5, 6, 7 );
print "tup1[0]: ", tup1[0]
print "tup2[1:5]: ", tup2[1:5]
以上實例輸出結果:
tup1[0]: physics
tup2[1:5]: [2, 3, 4, 5]
7.3 修改元組
元組中的元素是不允許修改的,但可以對元組進行連接組合。
tup3 = tup1 + tup2;
7.4 刪除元組
元組中的元素是不允許刪除的,單可以用del語句刪除整個元組。
del tup
7.5 元組的運算符
和字符串一樣,源組件可以使用+號和*號進行運算,這就意味着元組可以組合和復制,運算后生成新的元組。
7.6 元組的內置函數
元組包含了以下內置函數:
- cmp(tuple1,tuple2):比較兩個元組元素
- len(tuple):計算元組元素個數
- max(tuple):返回元組中元素最大值
- min(tuple):返回元組中元素最小值
- tuple(seq):將列表轉換為元組
- tuple的陷阱:當你定義一個tuple時,在定義的時候,tuple的元素就必須被確定下來。
8 淺拷貝
1 >>> a = ['hello', [123, 234]]
2 >>> b = a[:]
3 >>> [id(x) for x in a,b]
4 [4496003656, 4496066752]
5 >>> [id(x) for x in a]
[4496091584, 4495947536]
6 >>> [id(x) for x in b]
7 [4496091584, 4495947536]
Line3,4可以看出a, b地址不同,這符合list是可變的,應開辟不同空間。那淺拷貝就是拷貝了一個副本嗎?再看Line5 - 8,我們發現a, b中元素的地址是相同的。如果說字符串'hello'地址一致還能理解,但是第二個元素是list地址仍一致。 這就說明了淺拷貝的特點,只是將容器內的元素的地址復制了一份 。
接着我們嘗試修改a, b中的值:
>>> a[0] = 'world'
>>> a[1].append(345)
>>> print 'a = ', a, '\n\r', 'b = ', b
a = ['world', [123, 234, 345]]
b = ['hello', [123, 234, 345]]
a中第一個元素str改變,但是b中未改變;a中第二個元素改變,b中也改變。這就符合不可變的對象修改會開辟新的空間,可變的對象修改不會開辟新空間。也進一步證明了 淺拷貝僅僅是復制了容器中元素的地址 。
8.1 深拷貝
復制代碼 代碼如下:
>>> from copy import deepcopy
>>> a = ['hello', [123, 234]]
>>> b = deepcopy(a)
>>> [id(x) for x in a, b]
[4496066824, 4496066680]
>>> [id(x) for x in a]
[4496091584, 4496067040]
>>> [id(x) for x in b]
[4496091584, 4496371792]
深拷貝后,可以發現a, b地址以及a, b中元素地址均不同。這才是完全 拷貝了一個副本 。
修改a的值后:
復制代碼 代碼如下:
>>> a[0] = 'world'
>>> a[1].append(345)
>>> print 'a = ', a, '\n\r', 'b = ', b
a = ['world', [123, 234, 345]]
b = ['hello', [123, 234]]
從Line4,5中可以發現僅僅a修改了,b沒有任何修改。 因為b是一個完全的副本,元素地址均與a不同,a修改,b不受影響 。
總結:
- 賦值是將一個對象的地址賦值給一個變量,讓變量指向該地址( 舊瓶裝舊酒 )。
- 淺拷貝是在另一塊地址中創建一個新的變量或容器,但是容器內的元素的地址均是源對象的元素的地址的拷貝。也就是說新的容器中指向了舊的元素( 新瓶裝舊酒 )。
- 深拷貝是在另一塊地址中創建一個新的變量或容器,同時容器內的元素的地址也是新開辟的,僅僅是值相同而已,是完全的副本。也就是說( 新瓶裝新酒 )。
