摘要:本文是通過廖雪峰的網(wǎng)站學(xué)習(xí)而整理的真的是很好的教程,省得我花錢買書了,然后我沒有去再整理總結(jié)語法,而是直接通過寫出代碼段來體現(xiàn)自己的學(xué)習(xí),也方便以后的快速復(fù)習(xí)回顧。
不想再像以前那樣,什么都從頭開始學(xué)習(xí)語法、總結(jié)語法,這樣反而會過分糾結(jié)于語法,耽誤了開發(fā),畢竟語言的主要屬性是工具,次要的屬性是語言本身。
所以還是先熟練使用語言去進行開發(fā),等足夠熟悉了,再去研究語言本身(編譯原理……)。
另外對于算法、設(shè)計模式、數(shù)據(jù)結(jié)構(gòu)、網(wǎng)絡(luò)知識、操作系統(tǒng)…… 的學(xué)習(xí)可以專門針對性的學(xué)習(xí),當(dāng)然更好的方法是以使用語言為主線,通過具體的應(yīng)用和實踐來推動這些技術(shù)知識的學(xué)習(xí)。
本文是通過廖雪峰的網(wǎng)站學(xué)習(xí)而整理的(真的是很好的教程,省得我花錢買書了?。缓笪覜]有去再整理總結(jié)語法,而是直接通過寫出代碼段來體現(xiàn)自己的學(xué)習(xí),也方便以后的快速復(fù)習(xí)、回顧。畢竟學(xué)習(xí)一門語言不是一天可以完成的,所以本文也不是一蹴而就的,而是會一直更新。
也沒有必要再對代碼做過多的文字解釋,一切都能通過代碼本身體現(xiàn)。
交互式命令行在Python的交互式命令行寫程序,比如>>>print("hello world"),好處是一下就能得到結(jié)果,壞處是沒法保存,下次還想運行的時候,還要再敲一遍。
所以實際的開發(fā)中,我們使用一個文本編輯器來寫代碼,然后保存為一個文件,這樣程序就可以反復(fù)運行了。比如將print("heool world")寫在文檔里注意print前面不能有任何空格,并保存為 hello.py,然后使用命令行進入該文件所在的目錄,執(zhí)行python hello.py就可以解析執(zhí)行這個源文件了。
絕對不要使用windows自帶的記事本:記事本會自作聰明地在文件開始的地方加上幾個特殊字符(UTF-8 BOM),結(jié)果會導(dǎo)致程序運行出現(xiàn)莫名其妙的錯誤。
直接運行py文件能不能像.exe文件那樣直接運行.py文件呢?在Windows上是不行的,但是,在Mac和Linux上是可以的,方法是在.py文件(比如是hello.py)的第一行加上一個特殊的注釋:
#!/usr/bin/env python3 print("hello, world")
接著,通過命令行給hello.py以執(zhí)行權(quán)限:chmod a+x hello.py,然后就可以在文件所在目錄下直接輸入./hello.py運行。
這個和Shell有些像!
輸入和輸出 輸出>>>print("測試一個運算式", "1+2=", 1+2) 測試一個運算式 1+2= 3
注意遇到print里面將參數(shù)分開的逗號會輸出空格。
輸入>>>name = input() xumenger
當(dāng)你輸入完name = input()并按下回車后,Python交互式命令行就等待你的輸入,以這個例子,輸入xumenger,然后回車完成輸入,這時候輸入的字符串就存入到name變量里了。
綜合輸出輸入的例子編寫一個test.py文件
name = input("請你輸入你的姓名: ") print("hello", name)
input里面的字符串參數(shù)作為輸出提示用,然后等待輸入,輸入的字符串(比如xumenger)存入name,然后再輸出 hello xumenger。
input()和print()是在命令行下面最基本的輸入和輸出,但是,用戶也可以通過其他更高級的圖形界面完成輸入和輸出,比如,在網(wǎng)頁上的一個文本框輸入自己的名字,點擊“確定”后在網(wǎng)頁上看到輸出信息。
2015.09.06 23:40,明天開始學(xué)習(xí)Python基礎(chǔ),先去睡覺!
Python基礎(chǔ)Python語法簡單,采用縮進來控制邏輯。沒有規(guī)定是幾個空格還是Tab,但是按照約定俗成的管理,應(yīng)該始終堅持使用4個空格的縮進。在文本編輯器中,需要設(shè)置把Tab自動轉(zhuǎn)換為4個空格,確保不混用Tab和空格。
# print absolute value of an integer: a = 100 if a >= 0: print(a) else: print(-a)
以#開頭的語句是注釋,當(dāng)語句以:結(jié)尾時,縮進的語句視為代碼塊。
數(shù)據(jù)類型整數(shù)、浮點數(shù)
整數(shù)和浮點數(shù)在計算機內(nèi)部存儲的方式是不同的,整數(shù)運算永遠是精確的(除法難道也是精確的?是的!),而浮點數(shù)運算則可能會有四舍五入的誤差。
字符串(使用單引號或者雙引號引起來)
如果字符串內(nèi)部包含"又包含"怎么辦,需要用來轉(zhuǎn)義
print("I"m "OK"!")
表示:I"m "OK"!
判斷
if age==18 print("值為18") else print("值不是18")
布爾值(True、False,用and、or和not運算)
空值
用 None表示,None不能理解為0,因為0是有意義的,而None是一個特殊的空值。
變量
=是賦值號,另外Python是動態(tài)語言,變量本身類型不固定。與之對應(yīng)的是靜態(tài)語言,靜態(tài)語言在定義變量的時候必須指定變量的類型,如果賦值的時候類型不匹配,就會報錯,像C、C++、Java。
a="ABC"
Python解釋器解釋它時,,干了兩件事
在內(nèi)存中創(chuàng)建一個"ABC"的字符串
在內(nèi)存中創(chuàng)建了一個名為a的變量,并將它指向"ABC"
也可以把一個變量a賦值給另一個變量b,這個操作實際上是把變量b指向變量a所指向的數(shù)據(jù),例如下面的代碼:
a = "ABC" b = a a = "XYZ" print(b)
最后一行打印出變量b的內(nèi)容到底是"ABC"呢還是"XYZ"?如果從數(shù)學(xué)意義上理解,就會錯誤地得出b和a相同,也應(yīng)該是"XYZ",但實際上b的值是"ABC"。一步一步理解代碼
在內(nèi)存中創(chuàng)建 "ABC" 字符串
在內(nèi)存中創(chuàng)建 a 變量,并將 a 指向 "ABC"
在內(nèi)存中創(chuàng)建 b 變量,因為將 a 值賦給 b,所以這是b也指向 "ABC"
然后又在內(nèi)存中創(chuàng)建了 "XYZ" 字符串,并將 a 指向 "XYZ",但是此時b 還是指向 "ABC"
除法10/3 得到的結(jié)果是 3.3333333333333
9/3 得到的結(jié)果是 3.0
10//3 得到的結(jié)果是 3
10%3 得到的結(jié)果是 1
這個知識點以前我一直存在疑惑,廖雪峰的教程里面講得還是很好的,點擊這里認真看。重點是字符編碼的原理、現(xiàn)在計算機系統(tǒng)通用的字符編碼工作方式、Python中的編碼方式、亂碼的解釋。
在最新的Python 3版本中,字符串是以 Unicode編碼的,也就是說Python的字符串支持多種語言。
關(guān)于Python的字符串類型和bytes類型、在網(wǎng)絡(luò)傳輸或者保存到磁盤時候字符串類型與bytes類型的轉(zhuǎn)換,參考對應(yīng)的廖雪峰的 字符串和編碼 教程,有詳細的講解。
1個中文字符經(jīng)過UTF-8編碼后通常會占用3個字節(jié),而1個英文字符只占用1個字節(jié)。
格式化print("Hi, %s, you have $%d." % ("loser", 10))
輸出是:Hi, loser, you have $10
print("Age: %s, Gender: %s" % (25, True))
輸出是:Age: 25, Gender: True
列表:listlist是一種有序的集合用[],可以隨時添加和刪除其中的元素
mates = ["Machael", "Bob", "Tracy"] print("%s" % (len(mates)) print(mates[0]) #第一個元素 print(mates[3]) #越界報錯 print(mates[-1]) #倒數(shù)第一個元素 print(mates[-2]) #倒數(shù)第二個元素 print(mates[-4]) #越界報錯 mates.append("xumenger") #list是可變列表,現(xiàn)在是在list末尾追加元素 mates.insert(1,"Joker") #插入一個元素在第二個位置 mates.pop() #刪除末尾的元素 mates.pop(1) #刪除第二個元素 mates[1] = "change" #替換第2個元素 L= ["test", 123, True] #list里面可以是不同類型的元素 s= ["test", 1, ["asp", 2], True] #list的元素可以是另一個list list1 = ["test", True] list2 = [2, False, list1] print(list2[2][0]) #可以看成是一個二維數(shù)組,類似的還有三維、四維……數(shù)組,不過很少用到。元組:tuple
tuple和list很相似,但是tuple是一旦初始化就不能再修改的,用()
mates= ("xumeng", "joker", "test")
現(xiàn)在,mates這個tuple不能變了,它也沒有append(),insert()這樣的方法。其他獲取元素的方法和list是一樣的,你可以正常地使用mates[0],mates[-1],但不能賦值成另外的元素。
不可變的tuple有什么意義?因為tuple不可變,所以代碼更安全。如果可能,能用tuple代替list就盡量用tuple。
t=(1)定義的不是tuple,是1這個數(shù)!這是因為括號()既可以表示tuple,又可以表示數(shù)學(xué)公式中的小括號,這就產(chǎn)生了歧義,因此,Python規(guī)定,這種情況下,按小括號進行計算,計算結(jié)果自然是1。
要想定義只有一個元素的tuple,應(yīng)該這樣t=(1,)
“可變的tuple”,可以是tuple有一個list元素,然后里面的list可變,可以看教程中 對應(yīng)部分 通過展示內(nèi)存中的存儲原理來說明原因:
t = ("a", "b", ["A", "B"]) t[2][0] = "X"條件判斷
a = input("輸入你的年齡: ") age = int(a) #因為input輸入的是字符串,所以要轉(zhuǎn)換成整型 if age >= 18: #注意冒號 : print("adult, your age is", age) elif age >= 6: #注意冒號 : print("teenager, your age is", age) else: #注意冒號 : print("kid")循環(huán)
names = ["nn", "aa", "mm"]
for name in names: #注意冒號 :
print(name)
sum = 0
for x in[1, 2, 3, 4, 5]
sum = sum +x
print(sum)
sum = 0
for x in range(101): #range(101)就可以生成0-100的整數(shù)序列
sum = sum + x
print(sum)
sum = 0
n = 99
while n>0: #注意冒號:
sum = sum +n n= n-2
print(sum)
字典:dictPython內(nèi)置了字典:dict的支持,全稱為dictionary,在其他語言中也成為map,使用鍵-值(key-value)存儲,具有幾塊的查找速度,注意使用{}。
d = {"key1": 95, "key2": 54, "key3": 100} print(d["key1"]) #把數(shù)據(jù)放入dict的方法,除了初始化時指定外,還可以通過key放入 d["key4"] = 123 #由于一個key只能對應(yīng)一個value,所以,多次對一個key放入value,后面的值會把前面的值沖掉 d["key1"] = 111 if "key2" in d: #判斷某個鍵是不是在dict中 print("在") if get("key2", -1) == -1: #如果有"key2"則獲取對應(yīng)的value,否則就返回-1 print("不在") d.pop("key3") #使用pop刪除對應(yīng)的鍵和值
為什么dict查找速度這么快?因為dict的實現(xiàn)原理和查字典是一樣的。假設(shè)字典包含了1萬個漢字,我們要查某一個字,一個辦法是把字典從第一頁往后翻,直到找到我們想要的字為止,這種方法就是在list中查找元素的方法,list越大,查找越慢。
第二種方法是先在字典的索引表里(比如部首表)查這個字對應(yīng)的頁碼,然后直接翻到該頁,找到這個字。無論找哪個字,這種查找速度都非???,不會隨著字典大小的增加而變慢。
你可以猜到,這種key-value存儲方式,在放進去的時候,必須根據(jù)key算出value的存放位置,這樣,取的時候才能根據(jù)key直接拿到value。
請務(wù)必注意,dict內(nèi)部存放的順序和key放入的順序是沒有關(guān)系的。
dict可以用在需要高速查找的很多地方,在Python代碼中幾乎無處不在,正確使用dict非常重要,需要牢記的第一條就是dict的key必須是不可變對象。
這是因為dict根據(jù)key來計算value的存儲位置,如果每次計算相同的key得出的結(jié)果不同,那dict內(nèi)部就完全混亂了。這個通過key計算位置的算法稱為哈希算法(Hash)。
要保證hash的正確性,作為key的對象就不能變。在Python中,字符串、整數(shù)等都是不可變的,因此,可以放心地作為key。而list是可變的,就不能作為key。
setset和dict類似,也是一組key的集合,但是不存儲value,由于key不能重復(fù),所以在set中,沒有重復(fù)的key。
#要創(chuàng)建一個set,需要提供一個list作為輸入結(jié)合 s1 = set([1, 2, 3]) #重復(fù)元素在set中被過濾,比如下面的語句,其實只要1,2,3 s= set([1, 1, 2, 2, 2, 3, 3]) #通過add(key)添加元素,重復(fù)添加的元素只會保留一個 s.add(4) #remove(key) 刪除元素 s.remove(1,2,3) #set可以看成數(shù)學(xué)意義上的無序和無重復(fù)元素的集合,因此,兩個set可以做數(shù)學(xué)意義上的交集、并集等操作 s2 = set([1,2,3]) s3 = set([2,3,4]) s4 = s2 & s3 #s4是s2和s3的交集 s5 = s2 | s3 #s4是s2和s3的并集
set和dict的唯一區(qū)別僅在于沒有存儲對應(yīng)的value,但是,set的原理和dict一樣,所以,同樣不可以放入可變對象,因為無法判斷兩個可變對象是否相等,也就無法保證set內(nèi)部“不會有重復(fù)元素”。試試把list放入set,看看是否會報錯。
廖雪峰的 講解dict和set的文章 的最后通過說明內(nèi)存里面的原理講解了可變對象與不可變對象!很好的理解Python和內(nèi)存機制的一個知識點!
tuple雖然是不變對象,但試試把(1, 2, 3)和(1, [2, 3])放入dict或set中,并解釋結(jié)果。
s1 = set([(1,2,3), (2,3,4)]) #這樣的tuple可以放進set s2 = set([(1,2, [1,2]), (2,3, [6,8])]) #這樣的tuple不能放進set,這是“可變的tuple”
2015.09.07 23:45, 明天開始學(xué)習(xí) Python的函數(shù) ,現(xiàn)在趕緊睡覺,身體最重要!
函數(shù) 調(diào)用函數(shù)要調(diào)用一個函數(shù),需要知道函數(shù)的名稱和參數(shù),比如求絕對值的函數(shù)abs,只有一個參數(shù)。可以直接從Python的官方網(wǎng)站查看文檔:http://docs.python.org/3/library/functions.html#abs
也可以在交互式命令行通過help(abs)查看abs函數(shù)的幫助信息。
print(abs(-1)) print(max(1,2,3,4)) print(max(1,2,3)) print(int("123")) #強制類型轉(zhuǎn)換 print(float("12.34)) print(str(100)) print(bool(1)) #輸出True print(bool("")) #輸出False
函數(shù)名其實是一個指向函數(shù)對象的引用,完全可以把一個函數(shù)名賦值給一個變量,相當(dāng)于給這個函數(shù)起了一個別名:
a=abs print(a(-1)) m=max print(max(1,2,3))定義函數(shù)
在Python中,定義一個函數(shù)要使用def語句,依次寫出函數(shù)名、括號、括號里的參數(shù)和冒號: ,然后,在縮進塊中編寫函數(shù)體,函數(shù)的返回值用return語句返回。
def my_abs(x): if not isinstance(x, (int, float)): raise TypeError("bad operand type") if x>=0: return x else: return -x
上面的函數(shù)中,對參數(shù)類型做檢查,只允許整數(shù)和浮點數(shù)類型的參數(shù),否則就raise一個異常。如果有必要,可以先對參數(shù)的數(shù)據(jù)類型做檢查,就像這個函數(shù)定義,就可以保證只處理int和float,而假如傳入的是str就會拋出異常。
請注意,函數(shù)體內(nèi)部的語句在執(zhí)行時,一旦執(zhí)行到return時,函數(shù)就執(zhí)行完畢,并將結(jié)果返回。因此,函數(shù)內(nèi)部通過條件判斷和循環(huán)可以實現(xiàn)非常復(fù)雜的邏輯。
如果沒有return語句,函數(shù)執(zhí)行完畢后也會返回結(jié)果,只是結(jié)果為None。return None可以簡寫為return。
import math def move(x, y, step, angle=0): nx = x + step * math.cos(angle) ny = y - step * math.sin(angle) return nx, ny
import math語句表示導(dǎo)入math包,并允許后續(xù)代碼引用math包里的sin、cos等函數(shù)。上面的這個函數(shù)有兩個返回值,我們可以這樣調(diào)用
x, y = move(100, 100, 60, math, pi/6) print(x, y)
但是,其實這個只是假象,Python函數(shù)返回的仍然是單一值:
r = move(100, 100, 60, math.pi / 6) print(r) #得到和上面一樣的結(jié)果
原來返回值是一個tuple!但是,在語法上,返回一個tuple可以省略括號,而多個變量可以同時接收一個tuple,按位置賦給對應(yīng)的值,所以,Python的函數(shù)返回多值其實就是返回一個tuple,但寫起來更方便。
Python強大的函數(shù)參數(shù)廖雪峰的函數(shù)的參數(shù) 這一章講解了位置參數(shù)、默認參數(shù)、因為參數(shù)類型不是不變對象導(dǎo)致使用默認參數(shù)出現(xiàn)的"意外"、list和tuple與可變參數(shù)、dict與關(guān)鍵字參數(shù)、命名關(guān)鍵參數(shù)。
在Python中定義函數(shù),可以用必選參數(shù)、默認參數(shù)、可變參數(shù)、關(guān)鍵字參數(shù)和命名關(guān)鍵字參數(shù),這5種參數(shù)都可以組合使用,除了可變參數(shù)無法和命名關(guān)鍵字參數(shù)混合。但是請注意,參數(shù)定義的順序必須是:必選參數(shù)、默認參數(shù)、可變參數(shù)/命名關(guān)鍵字參數(shù)和關(guān)鍵字參數(shù)。
這個太他媽強大了??!但是有點沒看懂,確實純粹的死記硬背還是不太有效,可以等到具體項目應(yīng)用的時候在參考這篇教程!結(jié)合具體的應(yīng)用再來深入的理解,絕對事半功倍,現(xiàn)在就需要知道Python中有很強大的函數(shù)參數(shù)的語法,等到具體用的時候知道到哪里去找相關(guān)的資料就行了!
遞歸函數(shù)def fact(n) if n==1: return 1 return n* fact(n-1)
使用遞歸函數(shù)需要注意防止棧溢出。在計算機中,函數(shù)調(diào)用是通過棧(stack)這種數(shù)據(jù)結(jié)構(gòu)實現(xiàn)的,每當(dāng)進入一個函數(shù)調(diào)用,棧就會加一層棧幀,每當(dāng)函數(shù)返回,棧就會減一層棧幀。由于棧的大小不是無限的,所以,遞歸調(diào)用的次數(shù)過多,會導(dǎo)致棧溢出??梢栽囋噁act(1000)。
解決遞歸調(diào)用棧溢出的方法是通過尾遞歸優(yōu)化,具體應(yīng)用見廖雪峰的遞歸函數(shù) 的教程。
尾遞歸調(diào)用時,如果做了優(yōu)化,棧不會增長,因此,無論多少次調(diào)用也不會導(dǎo)致棧溢出。遺憾的是,大多數(shù)編程語言沒有針對尾遞歸做優(yōu)化,Python解釋器也沒有做優(yōu)化,所以,即使把上面的fact(n)函數(shù)改成尾遞歸方式,也會導(dǎo)致棧溢出。
高級特性掌握了Python的數(shù)據(jù)類型、語句和函數(shù),基本上就可以編寫出很多有用的程序了。
比如構(gòu)造一個1, 3, 5, 7, ..., 99的列表,可以通過循環(huán)實現(xiàn):
L = [] n = 1 while n <= 99: L.append(n) n = n + 2
取list的前一半的元素,也可以通過循環(huán)實現(xiàn)。
但是在Python中,代碼不是越多越好,而是越少越好。代碼不是越復(fù)雜越好,而是越簡單越好。用任何的語言編程都應(yīng)該是這樣。
基于這一思想,我們來介紹Python中非常有用的高級特性,1行代碼能實現(xiàn)的功能,決不寫5行代碼。請始終牢記,代碼越少,開發(fā)效率越高。
切片L = ["Michael", "Sarah", "Tracy", "Bob", "Jack"] L1 = L[:3] #["Michael", "Sarah", "Tracy"] L2 = L[1:3] #["Sarah", "Tracy"] L3 = L[-2:] #["Bob", "Jack"] L4 = L[-2:-1] #["Bob"] #list的第一個元素的索引是0,倒數(shù)第一個元素的索引是-1 LL=list(range(100)) #[1,2,3,...,99] LL1=L[-10:] #[90,91,...,99] 后10個數(shù) LL2=L[10:20] #[10,11,12,...,19] 前11-20個數(shù) LL3=L[:10:2] #[0,2,4,6,8] 前10個數(shù),每兩個取一個 LL4=L[::5] #[0,5,10,...,90,95] 所有數(shù),每5個取一個 LL5=L[:] #甚至什么都不寫,只寫[:]就可以原樣復(fù)制一個list
tuple也是一種list,唯一區(qū)別是tuple不可變。因此,tuple也可以用切片操作,只是操作的結(jié)果仍是tuple。
T=(0,1,2,3,4,5) T1=T[:3]
字符串"xxx"也可以看成是一種list,每個元素就是一個字符。因此,字符串也可以用切片操作,只是操作結(jié)果仍是字符串:
T="ABCDEFG" T1=T[:3] #"ABC" T2=T[::2] #"ACEG"
在很多編程語言中,針對字符串提供了很多各種截取函數(shù)(例如,substring),其實目的就是對字符串切片。Python沒有針對字符串的截取函數(shù),只需要切片一個操作就可以完成,非常簡單。
有了切片操作,很多地方循環(huán)就不再需要了。Python的切片非常靈活,一行代碼就可以實現(xiàn)很多行循環(huán)才能完成的操作。
迭代Python的for循環(huán)抽象程度要高于Java的for循環(huán),因為Python的for循環(huán)不僅可以用在list或tuple上,還可以作用在其他可迭代對象上。
list這種數(shù)據(jù)類型雖然有下標,但很多其他數(shù)據(jù)類型是沒有下標的,但是,只要是可迭代對象,無論有無下標,都可以迭代,比如dict就可以迭代。
d= {"a":1, "b":2, "c":3} for key in d: print(key) #輸出a c b
為什么輸出的結(jié)果是a c b,不是a b c,因為dict的存儲不是按照list的方式順序排列,所以,迭代出的結(jié)果順序很可能不一樣。關(guān)于dict的存儲的知識,請參見對應(yīng)的dict教程。
默認情況下,dict迭代的是key。如果要迭代value,可以用for value in d.values(),如果要同時迭代key和value,可以用for k, v in d.items()。
由于字符串也是可迭代對象,所以可以用于for循環(huán)。
for ch in "ABCD": print ch
所以,當(dāng)我們使用for循環(huán)時,只要作用于一個可迭代對象,for循環(huán)就可以正常運行,而我們不太關(guān)心該對象究竟是list還是其他數(shù)據(jù)類型。那么,如何判斷一個對象是可迭代對象呢?方法是通過collections模塊的Iterable類型判斷:
from collections import Iterable isinstance("abc", Iterable) # str是否可迭代 True isinstance([1,2,3], Iterable) # list是否可迭代 True isinstance(123, Iterable) # 整數(shù)是否可迭代 False
最后一個小問題,如果要對list實現(xiàn)類似Java那樣的下標循環(huán)怎么辦?Python內(nèi)置的enumerate函數(shù)可以把一個list變成索引-元素對,這樣就可以在for循環(huán)中同時迭代索引和元素本身:
for i, value in enumerate(["A", "B", "C"]): print(i, value)
上面的for循環(huán)里,同時引用了兩個變量,在Python里是很常見的,比如下面的代碼:
for x, y in [(1, 1), (2, 4), (3, 9)]: print(x, y)列表生成式
L=list(range(1,11)) #生成[1,2,3,4,5,6,7,8,9,10] L1=[x*x for x in range(1,11)] #生成[1*1,2*2,...,10*10]
寫列表生成式時,把要生成的元素比如x * x放到前面,后面跟for循環(huán),就可以把list創(chuàng)建出來,十分有用,多寫幾次,很快就可以熟悉這種語法。
for循環(huán)后面還可以加上if判斷,這樣我們就可以篩選出僅偶數(shù)的平方:
L= [x * x for x in range(1, 11) if x % 2 == 0] #[4, 16, 36, 64, 100]
還可以使用兩層循環(huán),可以生成全排列:
L= [m + n for m in "ABC" for n in "XYZ"] #["AX", "AY", "AZ", "BX", "BY", "BZ", "CX", "CY", "CZ"]
三層和三層以上的循環(huán)就很少用到了。
例程,列出當(dāng)前目錄下的所有文件和目錄名
import os # 導(dǎo)入os模塊,模塊的概念后面講到 L=[d for d in os.listdir(".")] # os.listdir可以列出文件和目錄 print(L)
for循環(huán)其實可以同時使用兩個甚至多個變量,比如dict的items()可以同時迭代key和value:
d = {"x": "A", "y": "B", "z": "C" } for k, v in d.items(): print(k, "=", v)
因此,列表生成式也可以使用兩個變量來生成list:
d = {"x": "A", "y": "B", "z": "C" } L= [k + "=" + v for k, v in d.items()]
把一個list中所有的字符串變成小寫:
L = ["Hello", "World", "IBM", "Apple"] L1= [s.lower() for s in L]生成器
通過列表生成式,我們可以直接創(chuàng)建一個列表。但是,受到內(nèi)存限制,列表容量肯定是有限的。而且,創(chuàng)建一個包含100萬個元素的列表,不僅占用很大的存儲空間,如果我們僅僅需要訪問前面幾個元素,那后面絕大多數(shù)元素占用的空間都白白浪費了。
所以,如果列表元素可以按照某種算法推算出來,那我們是否可以在循環(huán)的過程中不斷推算出后續(xù)的元素呢?這樣就不必創(chuàng)建完整的list,從而節(jié)省大量的空間。在Python中,這種一邊循環(huán)一邊計算的機制,稱為生成器:generator。
要創(chuàng)建一個generator,有很多種方法。第一種方法很簡單,只要把一個列表生成式的[]改成(),就創(chuàng)建了一個generator:
L = [x * x for x in range(10)] print(L) #[0, 1, 4, 9, 16, 25, 36, 49, 64, 81] g = (x * x for x in range(10)) #()是一個generator print(g) #at 0x1022ef630>
我們可以直接打印出list的每一個元素,但我們怎么打印出generator的每一個元素呢?如果要一個一個打印出來,可以通過next()函數(shù)獲得generator的下一個返回值。我們講過,generator保存的是算法,每次調(diào)用next(g),就計算出g的下一個元素的值,直到計算到最后一個元素,沒有更多的元素時,拋出StopIteration的錯誤。
但是,如果每次輸出都調(diào)用next(g)實在是太{{BANNED}}了,正確的方法是使用for循環(huán),因為generator也是可迭代對象:
g = (x*x for x in range(10)) for n in g print(n)
所以,我們創(chuàng)建了一個generator后,基本上永遠不會調(diào)用next(),而是通過for循環(huán)來迭代它,并且不需要關(guān)心StopIteration的錯誤。
generator非常強大。如果推算的算法比較復(fù)雜,用類似列表生成式的for循環(huán)無法實現(xiàn)的時候,還可以用函數(shù)來實現(xiàn)。這篇對應(yīng)的教程中還講了更為牛逼的generator的使用方法!
迭代器我們已經(jīng)知道,可以直接作用于for循環(huán)的數(shù)據(jù)類型有以下幾種:
一類是集合數(shù)據(jù)類型,如list、tuple、dict、set、str等;
一類是generator,包括生成器和帶yield的generator function。
這些可以直接作用于for循環(huán)的對象統(tǒng)稱為可迭代對象: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循環(huán),還可以被next()函數(shù)不斷調(diào)用并返回下一個值,直到最后拋出StopIteration錯誤表示無法繼續(xù)返回下一個值了。
可以被next()函數(shù)調(diào)用并不斷返回下一個值的對象稱為迭代器: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對象,但list、dict、str雖然是Iterable,卻不是Iterator。
把list、dict、str等Iterable變成Iterator可以使用iter()函數(shù):
isinstance(iter([]), Iterator) #True isinstance(iter("abc"), Iterator) #True
你可能會問,為什么list、dict、str等數(shù)據(jù)類型不是Iterator?
這是因為Python的Iterator對象表示的是一個數(shù)據(jù)流,Iterator對象可以被next()函數(shù)調(diào)用并不斷返回下一個數(shù)據(jù),直到?jīng)]有數(shù)據(jù)時拋出StopIteration錯誤??梢园堰@個數(shù)據(jù)流看做是一個有序序列,但我們卻不能提前知道序列的長度,只能不斷通過next()函數(shù)實現(xiàn)按需計算下一個數(shù)據(jù),所以Iterator的計算是惰性的,只有在需要返回下一個數(shù)據(jù)時它才會計算。
Iterator甚至可以表示一個無限大的數(shù)據(jù)流,例如全體自然數(shù)。而使用list是永遠不可能存儲全體自然數(shù)的。
凡是可作用于for循環(huán)的對象都是Iterable類型。
凡是可作用于next()函數(shù)的對象都是Iterator類型,它們表示一個惰性計算的序列。
Python的for循環(huán)本質(zhì)上就是通過不斷調(diào)用next()函數(shù)實現(xiàn)的,例如:
for x in [1, 2, 3, 4, 5]: pass
實際上完全等價于:
# 首先獲得Iterator對象: it = iter([1, 2, 3, 4, 5]) # 循環(huán): while True: try: # 獲得下一個值: x = next(it) except StopIteration: # 遇到StopIteration就退出循環(huán) break函數(shù)式編程
函數(shù)式編程的一個特點就是,允許把函數(shù)本身作為參數(shù)傳入另一個函數(shù),還允許返回一個函數(shù)!
Python對函數(shù)式編程提供部分支持。由于Python允許使用變量,因此,Python不是純函數(shù)式編程語言。
高階函數(shù)那么函數(shù)名是什么呢?函數(shù)名其實就是指向函數(shù)的變量!對于abs()這個函數(shù),完全可以把函數(shù)名abs看成變量,它指向一個可以計算絕對值的函數(shù)!
如果把abs指向其他對象,會有什么情況發(fā)生?
abs = 10 abs(-10)
報錯:
Traceback (most recent call last):
File "
TypeError: "int" object is not callable
把abs指向10后,就無法通過abs(-10)調(diào)用該函數(shù)了!因為abs這個變量已經(jīng)不指向求絕對值函數(shù)而是指向一個整數(shù)10!
當(dāng)然實際代碼絕對不能這么寫,這里是為了說明函數(shù)名也是變量。要恢復(fù)abs函數(shù),請重啟Python交互環(huán)境。
由于abs函數(shù)實際上是定義在__builtin__模塊中的,所以要讓修改abs變量的指向在其它模塊也生效,要用__builtin__.abs = 10。
既然變量可以指向函數(shù),函數(shù)的參數(shù)能接收變量,那么一個函數(shù)就可以接收另一個函數(shù)作為參數(shù),這種函數(shù)就稱之為高階函數(shù)。例子
def add(x, y, f): return f(x) + f(y)
可以這樣調(diào)用:
add(-5, 6, abs)
編寫高階函數(shù),就是讓函數(shù)的參數(shù)能夠接收別的函數(shù)。函數(shù)式編程就是指這種高度抽象的編程范式。
map/reduce我們先看map。map()函數(shù)接收兩個參數(shù),一個是函數(shù),一個是Iterable,map將傳入的函數(shù)依次作用到序列的每個元素,并把結(jié)果作為新的Iterator返回。
def f(x): return x*x r = map(f, [1,2,3,4,5,6,7,8,9]) print(list(r)) #[1,4,16,25,36,49,64,81]
再看reduce的用法。reduce把一個函數(shù)作用在一個序列[x1, x2, x3, ...]上,這個函數(shù)必須接收兩個參數(shù),reduce把結(jié)果繼續(xù)和序列的下一個元素做累積計算,其效果就是:
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
例子,比方說對一個序列求和,就可以用reduce實現(xiàn):
from functools import reduce
def add(x, y):
return x + y
print(reduce(add, [1, 3, 5, 7, 9])) #輸出25
這個例子本身沒多大用處,但是,如果考慮到字符串str也是一個序列,對上面的例子稍加改動,配合map(),我們就可以寫出把str轉(zhuǎn)換為int的函數(shù):
from functools import reduce def fn(x, y): return x * 10 + y def char2num(s): return {"0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8, "9": 9}[s] print(reduce(fn, map(char2num, "13579"))) #輸出13579
整理成一個str2int的函數(shù)就是:
from functools import reduce def str2int(s): def fn(x, y): return x * 10 + y def char2num(s): return {"0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8, "9": 9}[s] return reduce(fn, map(char2num, s))
還可以用lambda函數(shù)進一步簡化成:
from functools import reduce def char2num(s): return {"0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8, "9": 9}[s] def str2int(s): return reduce(lambda x, y: x * 10 + y, map(char2num, s))
也就是說,假設(shè)Python沒有提供int()函數(shù),你完全可以自己寫一個把字符串轉(zhuǎn)化為整數(shù)的函數(shù),而且只需要幾行代碼!
filterPython內(nèi)建的filter()函數(shù)用于過濾序列。
和map()類似,filter()也接收一個函數(shù)和一個序列。和map()不同的時,filter()把傳入的函數(shù)依次作用于每個元素,然后根據(jù)返回值是True還是False決定保留還是丟棄該元素。
例如,在一個list中,刪掉偶數(shù),只保留奇數(shù),可以這么寫:
def is_odd(n): return n % 2 == 1 list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15])) # 結(jié)果: [1, 5, 9, 15]
可見用filter()這個高階函數(shù),關(guān)鍵在于正確實現(xiàn)一個“篩選”函數(shù)。
注意到filter()函數(shù)返回的是一個Iterator,也就是一個惰性序列,所以要強迫filter()完成計算結(jié)果,需要用list()函數(shù)獲得所有結(jié)果并返回list。
sorted排序也是在程序中經(jīng)常用到的算法。無論使用冒泡排序還是快速排序,排序的核心是比較兩個元素的大小。如果是數(shù)字,我們可以直接比較,但如果是字符串或者兩個dict呢?直接比較數(shù)學(xué)上的大小是沒有意義的,因此,比較的過程必須通過函數(shù)抽象出來。通常規(guī)定,對于兩個元素x和y,如果認為x < y,則返回-1,如果認為x == y,則返回0,如果認為x > y,則返回1,這樣,排序算法就不用關(guān)心具體的比較過程,而是根據(jù)比較結(jié)果直接排序。
Python內(nèi)置的sorted()函數(shù)就可以對list進行排序:
sorted([36, 5, -12, 9, -21]) #[-21, -12, 5, 9, 36]
此外,sorted()函數(shù)也是一個高階函數(shù),它還可以接收一個key函數(shù)來實現(xiàn)自定義的排序,例如按絕對值大小排序:
sorted([36, 5, -12, 9, -21], key=abs) #[5, 9, -12, -21, 36] #key指定的函數(shù)將作用于list的每一個元素上,并根據(jù)key函數(shù)返回的結(jié)果進行排序。
我們再看一個字符串排序的例子:
sorted(["bob", "about", "Zoo", "Credit"]) #["Credit", "Zoo", "about", "bob"]
默認情況下,對字符串排序,是按照ASCII的大小比較的,由于"Z" < "a",結(jié)果,大寫字母Z會排在小寫字母a的前面。
現(xiàn)在,我們提出排序應(yīng)該忽略大小寫,按照字母序排序。要實現(xiàn)這個算法,不必對現(xiàn)有代碼大加改動,只要我們能用一個key函數(shù)把字符串映射為忽略大小寫排序即可。忽略大小寫來比較兩個字符串,實際上就是先把字符串都變成大寫(或者都變成小寫),再比較。
這樣,我們給sorted傳入key函數(shù),即可實現(xiàn)忽略大小寫的排序:
sorted(["bob", "about", "Zoo", "Credit"], key=str.lower) #["about", "bob", "Credit", "Zoo"]
要進行反向排序,不必改動key函數(shù),可以傳入第三個參數(shù)reverse=True:
sorted(["bob", "about", "Zoo", "Credit"], key=str.lower, reverse=True) #["Zoo", "Credit", "bob", "about"]
從上述例子可以看出,高階函數(shù)的抽象能力是非常強大的,而且,核心代碼可以保持得非常簡潔。
返回函數(shù)高階函數(shù)除了可以接受函數(shù)作為參數(shù)外,還可以把函數(shù)作為結(jié)果值返回。
我們來實現(xiàn)一個可變參數(shù)的求和。通常情況下,求和的函數(shù)是這樣定義的:
def calc_sum(*args): ax = 0 for n in args: ax = ax + n return ax
但是,如果不需要立刻求和,而是在后面的代碼中,根據(jù)需要再計算怎么辦?可以不返回求和的結(jié)果,而是返回求和的函數(shù):
def lazy_sum(*args): def sum(): ax = 0 for n in args: ax = ax + n return ax return sum
當(dāng)我們調(diào)用lazy_sum()時,返回的并不是求和結(jié)果,而是求和函數(shù):
f = lazy_sum(1, 3, 5, 7, 9) f
調(diào)用函數(shù)f時,才真正計算求和的結(jié)果:
f() #25閉包
注意到返回的函數(shù)在其定義內(nèi)部引用了局部變量args,所以,當(dāng)一個函數(shù)返回了一個函數(shù)后,其內(nèi)部的局部變量還被新函數(shù)引用,所以,閉包用起來簡單,實現(xiàn)起來可不容易。
另一個需要注意的問題是,返回的函數(shù)并沒有立刻執(zhí)行,而是直到調(diào)用了f()才執(zhí)行。我們來看一個例子:
def count(): fs = [] for i in range(1, 4): def f(): return i*i fs.append(f) return fs f1, f2, f3 = count()
在上面的例子中,每次循環(huán),都創(chuàng)建了一個新的函數(shù),然后,把創(chuàng)建的3個函數(shù)都返回了。
你可能認為調(diào)用f1(),f2()和f3()結(jié)果應(yīng)該是1,4,9,但實際結(jié)果是:
f1() #9 f2() #9 f3() #9
全部都是9!原因就在于返回的函數(shù)引用了變量i,但它并非立刻執(zhí)行。等到3個函數(shù)都返回時,它們所引用的變量i已經(jīng)變成了3,因此最終結(jié)果為9。
返回閉包時牢記的一點就是:返回函數(shù)不要引用任何循環(huán)變量,或者后續(xù)會發(fā)生變化的變量。
如果一定要引用循環(huán)變量怎么辦?方法是再創(chuàng)建一個函數(shù),用該函數(shù)的參數(shù)綁定循環(huán)變量當(dāng)前的值,無論該循環(huán)變量后續(xù)如何更改,已綁定到函數(shù)參數(shù)的值不變:
def count(): def f(j): def g(): return j*j return g fs = [] for i in range(1, 4): fs.append(f(i)) # f(i)立刻被執(zhí)行,因此i的當(dāng)前值被傳入f() return fs
再看看結(jié)果:
f1, f2, f3 = count() f1() #1 f2() #4 f3() #9
缺點是代碼較長,可利用lambda函數(shù)縮短代碼。
匿名函數(shù)當(dāng)我們在傳入函數(shù)時,有些時候,不需要顯式地定義函數(shù),直接傳入匿名函數(shù)更方便。
在Python中,對匿名函數(shù)提供了有限支持。還是以map()函數(shù)為例,計算f(x)=x2時,除了定義一個f(x)的函數(shù)外,還可以直接傳入匿名函數(shù):
list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9])) #[1, 4, 9, 16, 25, 36, 49, 64, 81]
通過對比可以看出,匿名函數(shù)lambda x: x * x實際上就是:
def f(x): return x * x
關(guān)鍵字lambda表示匿名函數(shù),冒號前面的x表示函數(shù)參數(shù)。
匿名函數(shù)有個限制,就是只能有一個表達式,不用寫return,返回值就是該表達式的結(jié)果。
用匿名函數(shù)有個好處,因為函數(shù)沒有名字,不必擔(dān)心函數(shù)名沖突。此外,匿名函數(shù)也是一個函數(shù)對象,也可以把匿名函數(shù)賦值給一個變量,再利用變量來調(diào)用該函數(shù):
f = lambda x: x * x f #at 0x101c6ef28> f(5) #25
同樣,也可以把匿名函數(shù)作為返回值返回,比如:
def build(x, y): return lambda: x * x + y * y裝飾器
def log(func): def wrapper(*args, **kw): print("call %s():" % func.__name__) return func(*argc, **kw) return wrapper
觀察上面的log,因為它是一個decorator,所以接受一個函數(shù)作為參數(shù),并返回一個函數(shù)。我們要借助Python的@語法,把decorator置于函數(shù)的定義處:
@log def now(): print("2015-3-25")
調(diào)用now()函數(shù),不僅會運行now()函數(shù)本身,還會在運行now()函數(shù)前打印一行日志:
now() #call now(): #2015-3-25
把@log放到now()函數(shù)的定義處,相當(dāng)于執(zhí)行了語句:
now = log(now)
由于log()是一個decorator,返回一個函數(shù),所以,原來的now()函數(shù)仍然存在,只是現(xiàn)在同名的now變量指向了新的函數(shù),于是調(diào)用now()將執(zhí)行新函數(shù),即在log()函數(shù)中返回的wrapper()函數(shù)。
wrapper()函數(shù)的參數(shù)定義是(args, *kw),因此,wrapper()函數(shù)可以接受任意參數(shù)的調(diào)用。在wrapper()函數(shù)內(nèi),首先打印日志,再緊接著調(diào)用原始函數(shù)。
在面向?qū)ο螅∣OP)的設(shè)計模式中,decorator被稱為裝飾模式。OOP的裝飾模式需要通過繼承和組合來實現(xiàn),而Python除了能支持OOP的decorator外,直接從語法層次支持decorator。Python的decorator可以用函數(shù)實現(xiàn),也可以用類實現(xiàn)。
decorator可以增強函數(shù)的功能,定義起來雖然有點復(fù)雜,但使用起來非常靈活和方便。
偏函數(shù)functools.partial就是幫助我們創(chuàng)建一個偏函數(shù)的,不需要我們自己定義int2(),可以直接使用下面的代碼創(chuàng)建一個新的函數(shù)int2:
import functools int2 = functools.partial(int, base=2) print(int2("1000000")) #64 print(int2("1010101")) #85
Python的functools模塊提供了很多有用的功能,其中一個就是偏函數(shù)(Partial function)。要注意,這里的偏函數(shù)和數(shù)學(xué)意義上的偏函數(shù)不一樣。
沒太看懂,還是等到具體研究一個項目源碼,以及自己做開發(fā)的時候再去結(jié)合實踐深入理解吧!
2015.09.08 23:59:00 明天繼續(xù)看 模塊 的教程,今天對很多知識點并沒有真正理解,都是有一些印象,所以必須等到自己研究源碼、自己開發(fā)的時候,結(jié)合運行的效果和理論知識去達到真正的深入的理解?,F(xiàn)在趕緊睡覺!
模塊在計算機程序的開發(fā)過程中,隨著程序代碼越寫越多,在一個文件里代碼就會越來越長,越來越不容易維護。
為了編寫可維護的代碼,我們把很多函數(shù)分組,分別放到不同的文件里,這樣,每個文件包含的代碼就相對較少,很多編程語言都采用這種組織代碼的方式。在Python中,一個.py文件就稱之為一個模塊(Module)。
引入了包以后,只要頂層的包名不與別人沖突,那所有模塊都不會與別人沖突?,F(xiàn)在,abc.py模塊的名字就變成了mycompany.abc,類似的,xyz.py的模塊名變成了mycompany.xyz。
請注意,每一個包目錄下面都會有一個__init__.py的文件,這個文件是必須存在的,否則,Python就把這個目錄當(dāng)成普通目錄,而不是一個包。__init__.py可以是空文件,也可以有Python代碼,因為__init__.py本身就是一個模塊,而它的模塊名就是mycompany。
類似的,可以有多級目錄,組成多級層次的包結(jié)構(gòu)。
使用模塊 安裝第三方模塊很多強大的第三方庫,要能夠充分利用好它們?yōu)槲曳?wù)?。?!
面向?qū)ο缶幊?/b>面向?qū)ο缶幊獭狾bject Oriented Programming,簡稱OOP,是一種程序設(shè)計思想。OOP把對象作為程序的基本單元,一個對象包含了數(shù)據(jù)和操作數(shù)據(jù)的函數(shù)。
面向過程的程序設(shè)計把計算機程序視為一系列的命令集合,即一組函數(shù)的順序執(zhí)行。為了簡化程序設(shè)計,面向過程把函數(shù)繼續(xù)切分為子函數(shù),即把大塊函數(shù)通過切割成小塊函數(shù)來降低系統(tǒng)的復(fù)雜度。
而面向?qū)ο蟮某绦蛟O(shè)計把計算機程序視為一組對象的集合,而每個對象都可以接收其他對象發(fā)過來的消息,并處理這些消息,計算機程序的執(zhí)行就是一系列消息在各個對象之間傳遞。
2015.09.22,明天繼續(xù)學(xué)習(xí)《面向?qū)ο缶幊獭?/p>
比如一個類的代碼如下
class Student(object): def __init__(self, name, score): self.name = name self.score = score def print_score(self): print("%s: %s" % (self.name, self.score))
可以這樣使用這個類創(chuàng)建對象
bart = Student("Bart Simpson", 59) lisa = Student("Lisa Simpson", 87) bart.print_score() lisa.print_score()
面向?qū)ο蟮脑O(shè)計思想是從自然界中來的,因為在自然界中,類(Class)和實例(Instance)的概念是很自然的。Class是一種抽象概念,比如我們定義的Class——Student,是指學(xué)生這個概念,而實例(Instance)則是一個個具體的Student,比如,Bart Simpson和Lisa Simpson是兩個具體的Student。
所以,面向?qū)ο蟮脑O(shè)計思想是抽象出Class,根據(jù)Class創(chuàng)建Instance。
面向?qū)ο蟮某橄蟪潭扔直群瘮?shù)要高,因為一個Class既包含數(shù)據(jù),又包含操作數(shù)據(jù)的方法。
數(shù)據(jù)封裝、繼承和多態(tài)是面向?qū)ο蟮娜筇攸c,我們后面會詳細講解。
類和實例關(guān)于面向?qū)ο笤O(shè)計其實和C++、Delphi……都很像,但是具體的語法可能不同,不過這都是一些表面化的東西。具體去參考Python的編程規(guī)范、語法就好了。
這篇教程里面有關(guān)于類、實例、實例的內(nèi)存地址……的講解,所以要好好看看!
__init__方法是類的構(gòu)造方法,self這個特殊變量的理解。
和普通的函數(shù)相比,在類中定義的函數(shù)只有一點不同,就是第一個參數(shù)永遠是實例變量self,并且,調(diào)用時,不用傳遞該參數(shù)。除此之外,類的方法和普通函數(shù)沒有什么區(qū)別,所以,你仍然可以用默認參數(shù)、可變參數(shù)、關(guān)鍵字參數(shù)和命名關(guān)鍵字參數(shù)。
要定義一個方法,除了第一個參數(shù)是self外,其他和普通函數(shù)一樣。要調(diào)用一個方法,只需要在實例變量上直接調(diào)用,除了self不用傳遞,其他參數(shù)正常傳入。
因為Python是靜態(tài)語言,所以語法上還會有其他更多的區(qū)別,所以一定要和其他的之前我了解的語言在語法方面區(qū)分開
訪問限制一些關(guān)于變量的權(quán)限、訪問限制、命名規(guī)范的說明??偟膩碚f就是,Python本身沒有任何機制阻止你干壞事,一切全靠自覺。
繼承和多態(tài)在繼承關(guān)系中,如果一個實例的數(shù)據(jù)類型是某個子類,那它的數(shù)據(jù)類型也可以被看做是父類。但是,反過來就不行。可以使用isistance()函數(shù)來進行判斷。
這篇教程很好的講解了多態(tài)的表現(xiàn)形式!!具體的編程語法、代碼實現(xiàn)的細節(jié),認真參考這篇教程?。?/p> 獲取對象信息
type()
isinstance()
dir():如果要獲得一個對象的所有屬性和方法,可以使用dir()函數(shù),它返回一個包含字符串的list,比如,獲得一個str對象的所有屬性和方法。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/37600.html
摘要:月份發(fā)布了第版,收到不少網(wǎng)友的良好建議,所以又抽空進行了完善,當(dāng)然也拖了不少時間。本書主要介紹的基本使用,這也是我一開始在學(xué)習(xí)過程中經(jīng)常用到的。第章實戰(zhàn),介紹了如何開發(fā)一個簡單的應(yīng)用。聲明本書由編寫,采用協(xié)議發(fā)布。 showImg(https://segmentfault.com/img/remote/1460000007484050?w=200&h=152); 書籍地址 head-f...
摘要:此文是記錄我在學(xué)習(xí)的過程,主要目的是怕學(xué)了后面的了前面的,方便復(fù)習(xí)。不得不承認,老外的課程確實比國內(nèi)的課程更有趣。所以提升性能的個關(guān)鍵降低電子需要行徑的距離提高每秒發(fā)射電子的次數(shù)。 此文是記錄我在udacity.com學(xué)習(xí)python的過程,主要目的是怕學(xué)了后面的wan了前面的,方便復(fù)習(xí)。也希望能幫到和我一樣的初學(xué)者,這個課程的是Udacity的《計算機基礎(chǔ)導(dǎo)論》,https://cl...
摘要:降采樣的目的是為了綜合所有不同清晰度的圖像進行關(guān)鍵點提取,這種關(guān)鍵點攜帶了不同清晰度的信息,對縮放具有不變性。是對的一種改進,主要特點是快速。的達到維,導(dǎo)致的比較耗時,使用哈爾小波轉(zhuǎn)換得到的方向,讓的降到維,減少了一半,提高了匹配速度。 尺度不變特征變換(Scale-invariant feature transform, 簡稱SIFT)是圖像局部特征提取的現(xiàn)代方法——基于區(qū)域/圖像塊...
摘要:寫在前面金三銀四又到了一年一度的跳槽季相信大家都在準備自己面試筆記我也針對自己工作中所掌握或了解的一些東西做了一個目錄總結(jié)方便自己復(fù)習(xí)詳細內(nèi)容會在之后一一對應(yīng)地補充上去有些在我的個人主頁筆記中也有相關(guān)記錄這里暫且放一個我的面試知識點目錄大家 寫在前面: 金三銀四, 又到了一年一度的跳槽季, 相信大家都在準備自己面試筆記, 我也針對自己工作中所掌握或了解的一些東西做了一個目錄總結(jié),方便自...
閱讀 3128·2021-11-10 11:36
閱讀 3322·2021-10-13 09:40
閱讀 6147·2021-09-26 09:46
閱讀 675·2019-08-30 15:55
閱讀 1419·2019-08-30 15:53
閱讀 1589·2019-08-29 13:55
閱讀 3005·2019-08-29 12:46
閱讀 3218·2019-08-29 12:34