- 學完了基礎中的基礎後,我們準備深入基礎中的函式、類和物件。
function函式:
正如英文單詞描述的,函式就是“功能”的意思,把完成一個功能所需要的程式碼打包起來放在一個函式下可以方便以後程式的重複呼叫,也能使整體程式碼條理清晰。正如前面用到的print(), input()之類的內建函式,這裡討論的函式為自定義涵數。
定義函式的格式:
def 函式名 (引數1,引數2,引數3…):
程式碼行
return – [可選項,如果不加,返回None]
函式的呼叫格式:
函式名(引數1,引數2,引數3)
函式名一般要小寫字母,當呼叫函式時,如果在後面的括號中加了引數,表明需要將這幾個引數傳到定義好的函式中去用。
定長傳參:
在定義的函式名後面的括號內必須要留有相對應數量的引數名(變數名)進行引數的接收,如果沒有特別指名引數賦值的變數,那麼引數將按照對應的位置進行引數傳遞,也叫位置傳參。如果在呼叫時使用接收引數的變數名進行了引數賦值,那麼引數將按指定的變數名位置進行引數傳遞,也叫關鍵字(變數名)傳參。當傳遞的引數多於收接收的引數量時就是報錯。如下
>>> def function1(para1, para2):
… print(para1,para2)
…
>>> function1(`Hello`, `World`)
Hello World
>>> function1(`World`,`Hello`)
World Hello
>>> function1(para2=`World`,para1=`Hello`)
Hello World
>>> function1(`How`,`are`,`you`)
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
TypeError: function1() takes 2 positional arguments but 3 were given
>>>
如果在定義函式時,引數的末尾有一個指定的引數值時,那麼這個引數就是預設引數,即在傳參時不寫相對應的引數值時,預設將使用預先定義好的數值。如下
>>> def function2(para1, para2, para3=`Cool`):
… print(para1, para2, para3)
…
>>> function2(`Hello`,`World`)
Hello World Cool
>>> function2(`How`,`are`,`you`)
How are you
>>>
不定長傳參:
當不確定要傳遞的引數有多少時,通常有下面幾種方法傳
使用 *變數名,作為引數,引數將會以元祖形式接收多出來的引數,輸出時如果使用*變數名,則將元祖內的元素以空格分隔的字串形式輸出,如果僅使用變數名,則以元祖方式輸出引數。
>>> def function3(para1, *para2):
… print(para1)
… print(para2)
… print(*para2)
… print(para1,para2)
… print(para1, *para2)
…
>>> function3(`how`,`do`,`you`,`do`,`?`)
how
(`do`, `you`, `do`, `?`)
do you do ?
how (`do`, `you`, `do`, `?`)
how do you do ?
>>>
使用 **變數名,作為引數,引數將會以字典形式接收多出來的引數,與元祖不同,字典變數不能直接輸出成字串。
>>> def function4(para1, **para2):
… print(para1)
… print(para2)
… print(**para2)
… print(para1, para2)
… print(para1, **para2)
…
>>> function4(`one`,`two`,`three`)
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
TypeError: function4() takes 1 positional argument but 3 were given
>>> function4(`one`,`two`=`2`,`three`=`3`)
File “<stdin>”, line 1
SyntaxError: keyword can`t be an expression
>>> function4(`one`,two=`2`,three=`3`)
one
{`two`: `2`, `three`: `3`}
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
File “<stdin>”, line 4, in function4
TypeError: `two` is an invalid keyword argument for print()
>>> function4(`one`,two=2, three=3)
one
{`two`: 2, `three`: 3}
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
File “<stdin>”, line 4, in function4
TypeError: `two` is an invalid keyword argument for print()
>>>
注意,如果引數中單獨使用一個*,那麼這個*後面的引數必須要使用關鍵字進行傳參, *號不能直接輸出,即它就像一個強制要求符,它後面的引數必須使用關鍵字傳參,如下
>>> def function5(para1, *, para2):
… print(para1)
… print(*)
File “<stdin>”, line 3
print(*)
^
SyntaxError: invalid syntax
>>> def function5(para1, *, para2):
… print(para1)
… print(para2)
… print(para1, para2)
…
>>> function5(`Hello`,`World`)
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
TypeError: function5() takes 1 positional argument but 2 were given
>>> function5(`Hello`,para2=`World`)
Hello
World
Hello World
>>> function5(para1=`Hello`,`World`)
File “<stdin>”, line 1
SyntaxError: positional argument follows keyword argument
>>>
return: 在函式最後加上return 可以指定函式執行完後想要返回的一個值,可以是變數也可以是固定的值,就看你需要返回什麼就根據需要寫這個表達試。如果不加return,那麼函式返回None比如:
>>> def test():
… print(`Hello World`)
… return `what`
…
>>> a = test()
Hello World
>>> print(a)
what
>>> def test1():
… sum = 1 + 1
… return sum
…
>>> print(test1())
2
>>>
- 瞭解了函式,我們就可以升級到類的概念了。本質上有點類似函式,函式是打包小的程式語句,而類就是打包函式用的,通常把執行同一類任務的函式歸為一類。類的定義如下, 用class開頭,類名首字母通常用大寫字母開頭,後面加小括號。
class ClassName():
變數1
變數2
def 函式1():
xxxxx
def 函式2():
xxxxx
由於類是一個大殼子,在類中包含了變數和函式。類裡面的變數叫做類的屬性,而類裡面的函式叫做類的方法。使用類,其實是在使用即呼叫類裡面的方法即函式。一個類裡面,在類函式外面層定義的變數可以被類內所有函式引用修改,也可以在類外面被引用修改。
在類內被函式引用類的變數時,需要在類方法上一層讓類先用@classmathod呼喚一下類方法,而在方法中的括號中加上(cls)表示收到,於是就可以快樂的使用類中的變數了,注意:Python中一定要注意大小寫,如:
>>> class Great():
… a = `Hello`
… b = `World`
… @classmethod
… def good(cls):
… print(cls.a)
… print(cls.b)
…
>>> great.good()
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
NameError: name `great` is not defined
>>> Great.good()
Hello
World
>>>
不難發現,在類外面引用類中的變數、方法格式都是先點名我要使用哪個類,然後通過點`.`來指定要用的變數或者方法名,即 類名.變數名/方法名。能呼叫了,就可以進行變數的引用、修改和方法的呼叫了。如:
>>> class Great():
… a = `Hello`
… b = `World`
… @classmethod
… def good(cls):
… print(cls.a)
… print(cls.b)
…
>>> great.good()
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
NameError: name `great` is not defined
>>> Great.good()
Hello
World
>>> Great.a = `How are`
>>> Great.b = `you?`
>>> Great.good()
How are
you?
>>>
那麼問題來了,類中直接定義的變數可以和外部進行‘溝通’,那麼類中的方法呢?因為方法就是函式,所以可以參考函式的引數傳遞,只是需要指名一下是給哪個類中的方法(函式)傳遞引數。如:
>>> class Great():
… def Get(para1, para2):
… print(para1, para2)
…
>>> Great.Get(`Hello`,`World`)
Hello World
>>> Great.Get(para1=`World`, para2=`Hello`)
World Hello
>>> Great.Get(para1=`Hello`, para2=`World`)
Hello World
>>>
- 說了半天的類,貌似類作用不是很大。其實不然,類的真正用途在於它的“例項化”,把類變成一樣例項物件,這種程式設計方式才是我們真正想要的,也就是所謂的“物件導向”的程式設計方式。這樣,別人造的輪子就能為我們所用了。
類的例項化其實就是把類“複製”到一個變數,此時我們就叫這個變數為“例項物件“”例項“”物件“,而類相當於這個例項的模板。當使用例項時,例項裡的屬性、方法改變不會影響類本身的屬性、方法,反之,當類(模板)的屬性、方法發生改變,會同步到例項裡的屬性和方法。誰讓類是例項的根呢。
需要注意的是,當類需要例項化的時候,類中的方法不能再有@classmethod和(cls)了,需要在方法中使用(self)作為第一個位置引數進行傳遞,雖然self不是強制性的名字,但這是程式界約定俗成的命名法。當類支援例項化的時候,self是所有方法中第一個預設位置的一個特殊引數。這也解釋了為什麼不能有@classmethod 和(cls)了,因為要做成一個能用的類(能例項化),讓類裡面的方法能讓大家使用就不能僅限於類裡面的引數傳遞了。同理,由於沒有了@classmethod (cls),類裡的方法就不能直接被呼叫了,需要例項化後才能使用。還個舉個例子吧,直接呼叫出錯,例項化後才能使用。
>>> class Great():
… def good(self):
… self.a = `Hello`
… self.b = `World`
… print(self.a, self.b)
…
>>> Great.good()
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
TypeError: good() missing 1 required positional argument: `self`
>>> OBJ = Great()
>>> OBJ.good()
Hello World
>>>
通過例項化後,向方法中傳遞引數的方法,本質上和傳遞引數給函式是一樣的,只是方法在接收引數時,第一位self不能動,剩下的自定義變數就行,如下:
>>> class Great():
… def good(self,para1,para2,para3):
… self.a = para1
… self.b = para2
… self.c = para3
… print(self.a, self.b,self.c)
…
>>> Test = Great()
>>> Test.good(`How`,`are`,`you?`)
How are you?
>>> Test.good(para2=`are`,para3=`you?`,para1=`How`)
How are you?
>>>
有了(self),一個類中的不同方法之間的引數就可以通過這個self進行傳遞了。常用的情況是當我們設定了一個”初始化“函式的時候。通常在初始化函式中,我們常常用來初始化各種引數,而這些引數通常會用於同一類中的其它方法。
初始化函式的定義:使用一個固定的名字__init__(self),初始化函式還有個特點是,當類被例項化的時候,會被自動呼叫。如下
>>> class Great():
… def __init__(self,para1,para2,para3):
… self.a = para1
… self.b = para2
… self.c = para3
… def good(self):
… print(self.a, self.b,self.c)
…
>>> Test = Great(`How`,`are`,`you?`)
>>> Test.good()
How are you?
>>>
類方法的重寫:當一個類中的方法不適合需求,需要更換時,可以通過在類的外部重新寫一個方法,將新方法賦值給類中的舊方法,以此實現新的方法覆蓋老的方法,達到替換的目的。
賦值語法:類.老方法 = 新方法 注意,因為不是呼叫,所以都不能有()。舉例如下:
>>> class Great():
… def __init__(self,para1,para2,para3):
… self.a = para1
… self.b = para2
… self.c = para3
… def good(self):
… print(self.a, self.b,self.c)
…
>>> Test = Great(`How`,`are`,`you?`)
>>> Test.good()
How are you?
>>>
>>> def bad(self):
… print(`Hello World`)
…
>>> Great.good = bad
>>> Test.good()
Hello World
>>>
類的繼承:當覺得老類中的方法有用但是功能還不夠用的情況下,可以通過定義一個新類,同時把老類繼承給新類來實現例項化後的新類能使用上老類中的方法(減少了新類中寫重複的方法)。
繼承語法:定義新類(老類):效果如下
>>> class Great():
… def __init__(self,para1,para2,para3):
… self.a = para1
… self.b = para2
… self.c = para3
… def good(self):
… print(self.a, self.b,self.c)
…
>>> class newGreat(Great):
… def newgood(self):
… print(`New Hello World`)
…
>>> Test = newGreat(`How`,`are`,`you?`)
>>> Test.good()
How are you?
>>> Test.newgood()
New Hello World
>>>