• 技术文章 >Python技术 >Python基础教程

    Python小白必学的面向对象

    silencementsilencement2019-07-13 13:58:36原创2442

    我们已经知道在Python中“一切皆对象”,每个对象都有特定的类型,现在让我们来尝试创建自己的类型——这需要使用class关键字来定义新的“类”(Class),类是用来生成对象的“模板”,对象则是其所属类的“实例”——以下是在交互模式中自定义Thing类,并调用其默认构造器生成一个Thing类的实例对象(注意:自定义类的命名规范要求单词首字母大写):

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    In [1]: class Thing:

       ...:     """最简单的自定义类"""

       ...:

     

    In [2]: type(Thing)

    Out[2]: type

     

    In [3]: t = Thing()

     

    In [4]: type(t)

    Out[4]: __main__.Thing

    可以看到,Thing对象属于type类型,是type类的一个实例;t对象属于Thing类型,是Thing类的一个实例——当你在程序中定义自己的类来生成实例对象,就算是“面向对象编程”(Object-Oriented Programming,简称OOP)。面向对象的编程方式使用类来模拟和组织现实世界的事物,可以令程序结构更灵活、条理更清晰。

    上面定义的Thing类所生成的实例对象并不能做什么事情,让我们再来创建一个包含了具体子语句的“船”类并生成两个“船”对象:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    In [5]: class Ship:

       ...:     """船类"""

       ...:     def __init__(self, name=None):

       ...:         """初始化船实例"""

       ...:         self.name = name  # 船名

       ...:         self.crew = 0  # 船员人数

       ...:     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类定义了一个特殊的“初始化”方法__init__,这样就能在调用构造器生成实例时加入新的实例“属性”(Property),所谓实例属性就是实例对象的“成员变量”,例如Ship类的实例增加了name和crew属性——从现实概念来理解,任何船都有船名和船员人数这两个数据,但每艘船又有各自的具体数据值。实例属性和实例方法是最常见的两种类成员,Python规定特殊类成员名以两个下划线开始和结束,其他类成员名遵循标准的变量命名规范,注意这里有一个细节概念:作为类成员的__init__属于函数,作为实例成员的__init__则属于方法,在类中定义函数时约定首个参数为“self”,它会指向所生成的实例对象以便操作其成员,对应的实例方法则无此参数,所以调用Ship构造器时只需传入一个参数(也可以不传入任何参数,因为name指定了默认值)。除了实例属性,你也可以定义新的实例方法,让实例能够做更多的事情——例如“船”类还有一个“船员加入”方法。

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    In [11]: help(Ship)

    Help on class Ship in module __main__:

     

    class Ship(builtins.object)

     |  船类

     

     |  Methods defined here:

     

     |  __init__(self, name=None)

     |      初始化船实例

     

     |  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': '郑和'}

    实例对象之所以拥有不必自定义而默认存在的特殊成员,是因为面向对象编程的一个重要特性“继承”(Inheritance)——使用继承机制能够将复杂的系统有机地组织起来,所有类都是同一个庞大家族的成员——定义类时可以在类名后加括号指定“基类”,新类将成为其“子类”;如果不指定基类,就默认为最基本的“object”类的子类。子类会继承基类的现有成员,子类定义属性和方法时如果与基类成员同名,就会“覆盖”基类成员。例如下面的程序定义了“船”类及其子类“战舰”类:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

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

     

     

    class Ship:

        """船类"""

        def __init__(self, name=None):

            """初始化船实例"""

            self.name = name  # 船名

            self.crew = 0  # 船员人数

     

        def join(self, number):

            """船员加入"""

            self.crew += number

            return self.crew

     

     

    class Warship(Ship):

        """战舰类"""

        def __init__(self, name=None, level=None):

            super().__init__(name)  # 先调用基类初始化方法

            self.level = level  # 舰级

     

     

    if __name__ == "__main__":

        ws1 = Warship("蓝色空间", "恒星级")

        ws1.join(500)

        print("{}战舰{}号,现有舰员{}人。".format(ws1.level, ws1.name, ws1.crew))

    可以注意到Warship类重新定义了__init__,这就会覆盖Ship类中的__init__,所以先调用基类的__init__才能继承到基类定义的实例属性name和crew。

    接下来的示例是一个简单的计算器:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    49

    50

    51

    52

    53

    54

    55

    56

    57

    58

    59

    60

    61

    62

    63

    64

    65

    66

    """tkcalc.pyw 简单的计算器

    """

    import tkinter as tk

     

     

    class Calc(tk.Tk):

        """计算器窗体类"""

        def __init__(self):

            """初始化实例"""

            tk.Tk.__init__(self)

            self.title("计算器")

            self.memory = 0  # 暂存数值

            self.create()

     

        def create(self):

            """创建界面"""

            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):

            """响应按钮"""

            if key == "=":  # 输出结果

                result = eval(self.entry.get())

                self.entry.insert(tk.END, " = " + str(result))

            elif key == "C":  # 清空输入框

                self.entry.delete(0, tk.END)

            elif key == "->M":  # 存入数值

                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->":  # 取出数值

                if self.memory:

                    self.entry.insert(tk.END, self.memory)

            elif key == "+/-":  # 正负翻转

                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()

    53d83e5766128ea75ef83f78749a7b4.png

    专题推荐:面向对象
    上一篇:Python中reduce函数和lambda表达式的学习 下一篇:5分钟搞定Python中函数的参数

    相关文章推荐

    • 大意了,这几道Python面试题没有答对,Python面试题精选

    全部评论我要评论

    © 2021 Python学习网 苏ICP备2021003149号-1

  • 取消发布评论
  • 

    Python学习网