編程入門(mén)11:Python面向?qū)ο?/h2>

上一篇:編程入門(mén)10:Python圖形界面

你已經(jīng)知道在Python中“一切皆對(duì)象”,每個(gè)對(duì)象都有特定的類(lèi)型,現(xiàn)在讓我們來(lái)嘗試創(chuàng)建自己的類(lèi)型——這需要使用class關(guān)鍵字來(lái)定義新的“類(lèi)”(Class),類(lèi)是用來(lái)生成對(duì)象的“模板”,對(duì)象則是其所屬類(lèi)的“實(shí)例”——以下是在交互模式中自定義Thing類(lèi),并調(diào)用其默認(rèn)構(gòu)造器生成一個(gè)Thing類(lèi)的實(shí)例對(duì)象(注意:自定義類(lèi)的命名規(guī)范要求單詞首字母大寫(xiě)):

In [1]: class Thing:
   ...:     """最簡(jiǎn)單的自定義類(lèi)"""
   ...: 

In [2]: type(Thing)
Out[2]: type

In [3]: t = Thing()

In [4]: type(t)
Out[4]: __main__.Thing

你可以看到,Thing對(duì)象屬于type類(lèi)型,是type類(lèi)的一個(gè)實(shí)例;t對(duì)象屬于Thing類(lèi)型,是Thing類(lèi)的一個(gè)實(shí)例——當(dāng)你在程序中定義自己的類(lèi)來(lái)生成實(shí)例對(duì)象,就算是“面向?qū)ο缶幊獭保∣bject-Oriented Programming,簡(jiǎn)稱(chēng)OOP)。面向?qū)ο蟮木幊谭绞绞褂妙?lèi)來(lái)模擬和組織現(xiàn)實(shí)世界的事物,可以令程序結(jié)構(gòu)更靈活、條理更清晰。


11_articleOOP.png

上面定義的Thing類(lèi)所生成的實(shí)例對(duì)象并不能做什么事情,讓我們?cè)賮?lái)創(chuàng)建一個(gè)包含了具體子語(yǔ)句的“船”類(lèi)并生成兩個(gè)“船”對(duì)象:

In [5]: class Ship:
   ...:     """船類(lèi)"""
   ...:     def __init__(self, name=None):
   ...:         """初始化船實(shí)例"""
   ...:         self.name = name  # 船名
   ...:         self.crew = 0  # 船員人數(shù)
   ...:     def join(self, number):
   ...:         """船員加入"""
   ...:         self.crew += number
   ...:         return self.crew
   ...:     

In [6]: s1 = Ship("鄭和")

In [7]: s1.crew = 200

In [8]: s2 = Ship("戚繼光")

In [9]: s2.join(100)
Out[9]: 100

In [10]: s2.crew
Out[10]: 100

Ship類(lèi)定義了一個(gè)特殊的“初始化”方法__init__,這樣就能在調(diào)用構(gòu)造器生成實(shí)例時(shí)加入新的實(shí)例“屬性”(Property),所謂實(shí)例屬性就是實(shí)例對(duì)象的“成員變量”,例如Ship類(lèi)的實(shí)例增加了name和crew屬性——從現(xiàn)實(shí)概念來(lái)理解,任何船都有船名和船員人數(shù)這兩個(gè)數(shù)據(jù),但每艘船又有各自的具體數(shù)據(jù)值。實(shí)例屬性和實(shí)例方法是最常見(jiàn)的兩種類(lèi)成員,Python規(guī)定特殊類(lèi)成員名以?xún)蓚€(gè)下劃線開(kāi)始和結(jié)束,其他類(lèi)成員名遵循標(biāo)準(zhǔn)的變量命名規(guī)范,注意這里有一個(gè)細(xì)節(jié)概念:作為類(lèi)成員的__init__屬于函數(shù),作為實(shí)例成員的__init__則屬于方法,在類(lèi)中定義函數(shù)時(shí)約定首個(gè)參數(shù)為“self”,它會(huì)指向所生成的實(shí)例對(duì)象以便操作其成員,對(duì)應(yīng)的實(shí)例方法則無(wú)此參數(shù),所以調(diào)用Ship構(gòu)造器時(shí)只需傳入一個(gè)參數(shù)(也可以不傳入任何參數(shù),因?yàn)閚ame指定了默認(rèn)值)。除了實(shí)例屬性,你也可以定義新的實(shí)例方法,讓實(shí)例能夠做更多的事情——例如“船”類(lèi)還有一個(gè)“船員加入”方法。

In [11]: help(Ship)
Help on class Ship in module __main__:

class Ship(builtins.object)
 |  船類(lèi)
 |  
 |  Methods defined here:
 |  
 |  __init__(self, name=None)
 |      初始化船實(shí)例
 |  
 |  join(self, number)
 |      船員加入
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)


In [12]: type(Ship.__init__)
Out[12]: function

In [13]: type(s2.__init__)
Out[13]: method

In [14]: s1.__dict__
Out[14]: {'crew': 200, 'name': '鄭和'}

實(shí)例對(duì)象之所以擁有不必自定義而默認(rèn)存在的特殊成員,是因?yàn)槊嫦驅(qū)ο缶幊痰囊粋€(gè)重要特性“繼承”(Inheritance)——使用繼承機(jī)制能夠?qū)?fù)雜的系統(tǒng)有機(jī)地組織起來(lái),所有類(lèi)都是同一個(gè)龐大家族的成員——定義類(lèi)時(shí)可以在類(lèi)名后加括號(hào)指定“基類(lèi)”,新類(lèi)將成為其“子類(lèi)”;如果不指定基類(lèi),就默認(rèn)為最基本的“object”類(lèi)的子類(lèi)。子類(lèi)會(huì)繼承基類(lèi)的現(xiàn)有成員,子類(lèi)定義屬性和方法時(shí)如果與基類(lèi)成員同名,就會(huì)“覆蓋”基類(lèi)成員。例如下面的程序定義了“船”類(lèi)及其子類(lèi)“戰(zhàn)艦”類(lèi):

"""ship.py 船的家族"""


class Ship:
    """船類(lèi)"""
    def __init__(self, name=None):
        """初始化船實(shí)例"""
        self.name = name  # 船名
        self.crew = 0  # 船員人數(shù)

    def join(self, number):
        """船員加入"""
        self.crew += number
        return self.crew


class Warship(Ship):
    """戰(zhàn)艦類(lèi)"""
    def __init__(self, name=None, level=None):
        super().__init__(name)  # 先調(diào)用基類(lèi)初始化方法
        self.level = level  # 艦級(jí)


if __name__ == "__main__":
    ws1 = Warship("藍(lán)色空間", "恒星級(jí)")
    ws1.join(500)
    print("{}戰(zhàn)艦{}號(hào),現(xiàn)有艦員{}人。".format(ws1.level, ws1.name, ws1.crew))

你可以注意到Warship類(lèi)重新定義了__init__,這就會(huì)覆蓋Ship類(lèi)中的__init__,所以先調(diào)用基類(lèi)的__init__才能繼承到基類(lèi)定義的實(shí)例屬性name和crew。

接下來(lái)的示例是一個(gè)簡(jiǎn)單的計(jì)算器:

"""tkcalc.pyw 簡(jiǎn)單的計(jì)算器
"""
import tkinter as tk


class Calc(tk.Tk):
    """計(jì)算器窗體類(lèi)"""
    def __init__(self):
        """初始化實(shí)例"""
        tk.Tk.__init__(self)
        self.title("計(jì)算器")
        self.memory = 0  # 暫存數(shù)值
        self.create()

    def create(self):
        """創(chuàng)建界面"""
        btn_list = ["C", "M->", "->M", "/",
                    "7", "8", "9", "*",
                    "4", "5", "6", "-",
                    "1", "2", "3", "+",
                    "+/-", "0", ".", "="]
        r = 1
        c = 0
        for b in btn_list:
            self.button = tk.Button(self, text=b, width=5,
                                    command=(lambda x=b: self.click(x)))
            self.button.grid(row=r, column=c, padx=3, pady=6)
            c += 1
            if c > 3:
                c = 0
                r += 1
        self.entry = tk.Entry(self, width=24, borderwidth=2,
                              bg="yellow", font=("Consolas", 12))
        self.entry.grid(row=0, column=0, columnspan=4, padx=8, pady=6)

    def click(self, key):
        """響應(yīng)按鈕"""
        if key == "=":  # 輸出結(jié)果
            result = eval(self.entry.get())
            self.entry.insert(tk.END, " = " + str(result))
        elif key == "C":  # 清空輸入框
            self.entry.delete(0, tk.END)
        elif key == "->M":  # 存入數(shù)值
            self.memory = self.entry.get()
            if "=" in self.memory:
                ix = self.memory.find("=")
                self.memory = self.memory[ix + 2:]
            self.title("M=" + self.memory)
        elif key == "M->":  # 取出數(shù)值
            if self.memory:
                self.entry.insert(tk.END, self.memory)
        elif key == "+/-":  # 正負(fù)翻轉(zhuǎn)
            if "=" in self.entry.get():
                self.entry.delete(0, tk.END)
            elif self.entry.get()[0] == "-":
                self.entry.delete(0)
            else:
                self.entry.insert(0, "-")
        else:  # 其他鍵
            if "=" in self.entry.get():
                self.entry.delete(0, tk.END)
            self.entry.insert(tk.END, key)


if __name__ == "__main__":
    Calc().mainloop()
11_calc.png

程序窗體繼承自tkinter.Tk類(lèi),要加部件就定義實(shí)例屬性,要做事情就使用實(shí)例方法,這就是OOP的方式。

——編程原來(lái)這樣……

編程小提示

這次給大家分享的是“Python資源大全中文版”,好用的東西都在其中了……
https://github.com/jobbole/awesome-python-cn

下一篇:編程入門(mén)12:Python異常處理

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容