• Python武器库开发-面向对象篇(五)


    面向对象篇(五)

    面向对象编程 是最有效的软件编写方法之一。在面向对象编程中,你编写表示现实世界中的事物和情景的类,并基于这些类来创建对象。编写类时,你定义一大类对象都有的通用行为。基于类创建对象 时,每个对象都自动具备这种通用行为,然后可根据需要赋予每个对象独特的个性。使用面向对象编程可模拟现实情景,其逼真程度达到了令你惊讶的地步。

    根据类来创建对象被称为实例化 ,这让你能够使用类的实例。在本章中,你将编写一些类并创建其实例。你将指定可在实例中存储什么信息,定义可对这些实例执行哪些操作。你还将编写一些类来扩展既有类的功能,让相似的类能够高效地共享代码。你将把自己编写的类存储在模块中,并在自己的程序文件中导入其他程序员编写的类。

    理解面向对象编程有助于你像程序员那样看世界,还可以帮助你真正明白自己编写的代码:不仅是各行代码的作用,还有代码背后更宏大的概念。了解类背后的概念可培养逻辑思维,让你能够通过编写程序来解决遇到的几乎任何问题。

    随着面临的挑战日益严峻,类还能让你以及与你合作的其他程序员的生活更轻松。如果你与其他程序员基于同样的逻辑来编写代码,你们就能明白对方所做的工作;你编写的程序将能被众多合作者所理解,每个人都能事半功倍。

    类和对象

    使用类几乎可以模拟任何东西。下面来编写一个表示小狗的简单类Dog ——它表示的不是特定的小狗,而是任何小狗。对于大多数宠物狗,我们都知道些什么呢?它们都有名字和年龄;我们还知道,大多数小狗还会蹲下和打滚。由于大多数小狗都具备上述两项信息(名字和年龄)和两种行为(蹲下和打滚),我们的Dog 类将包含它们。这个类让Python知道如何创建表示小狗的对象。编写这个类后,我们将使用它来创建表示特定小狗的实例。

    根据Dog 类创建的每个实例都将存储名字和年龄。我们赋予了每条小狗蹲下(sit() )和打滚(roll_over() )的能力:

    class Dog():
        """一次模拟小狗的简单尝试"""
    
        def __init__(self, name, age):
              """初始化属性name和age"""
            self.name = name
            self.age = age
    
        def sit(self):
            """模拟小狗被命令时蹲下"""
            print(self.name.title() + " is now sitting.")
    
        def roll_over(self):
            """模拟小狗被命令时打滚"""
            print(self.name.title() + " rolled over!")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    首先,我们定义了一个名为Dog 的类。根据约定,在Python中,首字母大写的名称指的是类。这个类定义中的括号是空的,因为我们要从空白创建这个类。然后,我们编写了一个文档字符串,对这个类的功能作了描述。

    • 方法__init__()

    类中的函数称为方法 ;你前面学到的有关函数的一切都适用于方法,就目前而言,唯一重要的差别是调用方法的方式。代码中的方法__init__() 是一个特殊的方法,每当你根据Dog 类创建新实例时,Python都会自动运行它。在这个方法的名称中,开头和末尾各有两个下划线,这是一种约定,旨在避免Python默认方法与普通方法发生名称冲突。

    我们将方法__init__() 定义成了包含三个形参:self 、name 和age 。在这个方法的定义中,形参self 必不可少,还必须位于其他形参的前面。为何必须在方法定义中包含形参self 呢?因为Python调用这个__init__() 方法来创建Dog 实例时,将自动传入实参self 。每个与类相关联的方法调用都自动传递实参self ,它是一个指向实例本身的引用,让实例能够访问类中的属性和方法。我们创建Dog 实例时,Python将调用Dog 类的方法__init__() 。我们将通过实参向Dog() 传递名字和年龄;self 会自动传递,因此我们不需要传递它。每当我们根据Dog 类创建实例时,都只需给最后两个形参(name 和age )提供值。

    接下来我们定义的两个变量都有前缀self 。以self 为前缀的变量都可供类中的所有方法使用,我们还可以通过类的任何实例来访问这些变量。self.name = name 获取存储在形参name 中的值,并将其存储到变量name 中,然后该变量被关联到当前创建的实例。self.age = age 的作用与此类似。像这样可通过实例访问的变量称为属性 。

    Dog 类还定义了另外两个方法:sit() 和roll_over() 。由于这些方法不需要额外的信息,如名字或年龄,因此它们只有一个形参self 。我们后面将创建的实例能够访问这些方法,换句话说,它们都会蹲下和打滚。当前,sit() 和roll_over() 所做的有限,它们只是打印一条消息,指出小狗正蹲下或打滚。但可以扩展这些方法以模拟实际情况:如果这个类包含在一个计算机游戏中,这些方法将包含创建小狗蹲下和打滚动画效果的代码。如果这个类是用于控制机器狗的,这些方法将引导机器狗做出蹲下和打滚的动作。

    下面来创建一个表示特定小狗的实例:

    class Dog():
        """一次模拟小狗的简单尝试"""
    
        def __init__(self, name, age):
              """初始化属性name和age"""
              self.name = name
              self.age = age
    
        def sit(self):
            """模拟小狗被命令时蹲下"""
            print(self.name.title() + " is now sitting.")
    
        def roll_over(self):
            """模拟小狗被命令时打滚"""
            print(self.name.title() + " rolled over!")
    
    my_dog = Dog('willie', 6)
    print("My dog's name is " + my_dog.name.title() + ".")
    print("My dog is " + str(my_dog.age) + " years old.")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    这里使用的是前一个示例中编写的Dog 类。首先,我们让Python创建一条名字为’willie’ 、年龄为6 的小狗。遇到这行代码时,Python使用实参’willie’ 和6 调用Dog 类中的方法__init__() 。方法__init__() 创建一个表示特定小狗的示例,并使用我们提供的值来设置属性name 和age 。方法__init__() 并未显式地包含return 语句,但Python自动返回一个表示这条小狗的实例。我们将这个实例存储在变量my_dog 中。在这里,命名约定很有用:我们通常可以认为首字母大写的名称(如Dog )指的是类,而小写的名称(如my_dog )指的是根据类创建的实例。代码运行结果如下:

    在这里插入图片描述

    访问属性

    要访问实例的属性,可使用句点表示法。我们编写了如下代码来访问my_dog 的属性name 的值:

    class Dog():
        """一次模拟小狗的简单尝试"""
    
        def __init__(self, name, age):
              """初始化属性name和age"""
              self.name = name
              self.age = age
    
        def sit(self):
            """模拟小狗被命令时蹲下"""
            print(self.name.title() + " is now sitting.")
    
        def roll_over(self):
            """模拟小狗被命令时打滚"""
            print(self.name.title() + " rolled over!")
    
    my_dog = Dog('willie', 6)
    print(my_dog.name)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    输出结果如下:

    在这里插入图片描述

    调用方法

    根据Dog 类创建实例后,就可以使用句点表示法来调用Dog 类中定义的任何方法。下面来让小狗蹲下和打滚:

    class Dog():
        """一次模拟小狗的简单尝试"""
    
        def __init__(self, name, age):
              """初始化属性name和age"""
              self.name = name
              self.age = age
    
        def sit(self):
            """模拟小狗被命令时蹲下"""
            print(self.name.title() + " is now sitting.")
    
        def roll_over(self):
            """模拟小狗被命令时打滚"""
            print(self.name.title() + " rolled over!")
    
    if __name__ == '__main__':
        my_dog = Dog('willie', 6)
        my_dog.sit()
        my_dog.roll_over()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    要调用方法,可指定实例的名称(这里是my_dog )和要调用的方法,并用句点分隔它们。遇到代码my_dog.sit() 时,Python在类Dog 中查找方法sit() 并运行其代码。Python以同样的方式解读代码my_dog.roll_over() 。

    Willie按我们的命令做了:

    在这里插入图片描述

    继承

    编写类时,并非总是要从空白开始。如果你要编写的类是另一个现成类的特殊版本,可使用继承 。一个类继承 另一个类时,它将自动获得另一个类的所有属性和方法;原有的类称为父类 ,而新类称为子类 。子类继承了其父类的所有属性和方法,同时还可以定义自己的属性和方法。

    创建子类的实例时,Python首先需要完成的任务是给父类的所有属性赋值。为此,子类的方法__init__() 需要父类施以援手。

    例如,下面来模拟电动汽车。电动汽车是一种特殊的汽车,因此我们可以在前面创建的Car 类的基础上创建新类ElectricCar ,这样我们就只需为电动汽车特有的属性和行为编写代码。

    下面来创建一个简单的ElectricCar 类版本,它具备Car 类的所有功能:

    class Car():
          """一次模拟汽车的简单尝试"""
          def __init__(self, make, model, year):
              self.make = make
              self.model = model
              self.year = year
              self.odometer_reading = 0
    
          def get_descriptive_name(self):
              long_name = str(self.year) + ' ' + self.make + ' ' + self.model
              return long_name.title()
    
          def read_odometer(self):
              print("This car has " + str(self.odometer_reading) + " miles on it.")
    
          def update_odometer(self, mileage):
              if mileage >= self.odometer_reading:
                  self.odometer_reading = mileage
              else:
                  print("You can't roll back an odometer!")
    
          def increment_odometer(self, miles):
              self.odometer_reading += miles
    
    class ElectricCar(Car):
          """电动汽车的独特之处"""
          def __init__(self, make, model, year):
              """初始化父类的属性"""
              super().__init__(make, model, year)
    
    if __name__ == '__main__':
        my_tesla = ElectricCar('tesla', 'model s', 2016)
        print(my_tesla.get_descriptive_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
    • 33

    首先是Car 类的代码。创建子类时,父类必须包含在当前文件中,且位于子类前面。然后,我们定义了子类ElectricCar 。定义子类时,必须在括号内指定父类的名称。方法__init__() 接受创建Car 实例所需的信息。

    接下来的super() 是一个特殊函数,帮助Python将父类和子类关联起来。这行代码让Python调用ElectricCar 的父类的方法__init__() ,让ElectricCar 实例包含父类的所有属性。父类也称为超类 (superclass),名称super因此而得名。

    为测试继承是否能够正确地发挥作用,我们尝试创建一辆电动汽车,但提供的信息与创建普通汽车时相同。随后,我们创建ElectricCar 类的一个实例,并将其存储在变量my_tesla 中。这行代码调用ElectricCar 类中定义的方法__init__() ,后者让Python调用父类Car 中定义的方法__init__() 。我们提供了实参’tesla’ 、‘model s’ 和2016 。

    除方法__init__() 外,电动汽车没有其他特有的属性和方法。当前,我们只想确认电动汽车具备普通汽车的行为:

    在这里插入图片描述

    让一个类继承另一个类后,可添加区分子类和父类所需的新属性和方法。

    下面来添加一个电动汽车特有的属性(电瓶),以及一个描述该属性的方法。我们将存储电瓶容量,并编写一个打印电瓶描述的方法:

    class Car():
          """一次模拟汽车的简单尝试"""
          def __init__(self, make, model, year):
              self.make = make
              self.model = model
              self.year = year
              self.odometer_reading = 0
    
          def get_descriptive_name(self):
              long_name = str(self.year) + ' ' + self.make + ' ' + self.model
              return long_name.title()
    
          def read_odometer(self):
              print("This car has " + str(self.odometer_reading) + " miles on it.")
    
          def update_odometer(self, mileage):
              if mileage >= self.odometer_reading:
                  self.odometer_reading = mileage
              else:
                  print("You can't roll back an odometer!")
    
          def increment_odometer(self, miles):
              self.odometer_reading += miles
    
    class ElectricCar(Car):
          """Represent aspects of a car, specific to electric vehicles."""
    
          def __init__(self, make, model, year):
              """
              电动汽车的独特之处
              初始化父类的属性,再初始化电动汽车特有的属性
              """
              super().__init__(make, model, year)
              self.battery_size = 70
          def describe_battery(self):
                  """打印一条描述电瓶容量的消息"""
                  print("This car has a " + str(self.battery_size) + "-kWh battery.")
    
    
    if __name__ == '__main__':
        my_tesla = ElectricCar('tesla', 'model s', 2016)
        print(my_tesla.get_descriptive_name())
        my_tesla.describe_battery()
    
    • 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

    首先,我们添加了新属性self.battery_size ,并设置其初始值(如70 )。根据ElectricCar 类创建的所有实例都将包含这个属性,但所有Car 实例都不包含它。然后,我们还添加了一个名为describe_battery() 的方法,它打印有关电瓶的信息。我们调用这个方法时,将看到一条电动汽车特有的描述:

    在这里插入图片描述

    对于ElectricCar 类的特殊化程度没有任何限制。模拟电动汽车时,你可以根据所需的准确程度添加任意数量的属性和方法。如果一个属性或方法是任何汽车都有的,而不是电动汽车特有的,就应将其加入到Car 类而不是ElectricCar 类中。这样,使用Car 类的人将获得相应的功能,而ElectricCar 类只包含处理电动汽车特有属性和行为的代码

    多继承

    #类定义
    class people:
        #定义基本属性
        name = ''
        age = 0
        #定义私有属性,私有属性在类外部无法直接进行访问
        __weight = 0
        #定义构造方法
        def __init__(self,n,a,w):
            self.name = n
            self.age = a
            self.__weight = w
        def speak(self):
            print("%s 说: 我 %d 岁。" %(self.name,self.age))
     
    #单继承示例
    class student(people):
        grade = ''
        def __init__(self,n,a,w,g):
            #调用父类的构函
            people.__init__(self,n,a,w)
            self.grade = g
        #覆写父类的方法
        def speak(self):
            print("%s 说: 我 %d 岁了,我在读 %d 年级"%(self.name,self.age,self.grade))
     
    #另一个类,多继承之前的准备
    class speaker():
        topic = ''
        name = ''
        def __init__(self,n,t):
            self.name = n
            self.topic = t
        def speak(self):
            print("我叫 %s,我是一个演说家,我演讲的主题是 %s"%(self.name,self.topic))
     
    #多继承
    class sample(speaker,student):
        a =''
        def __init__(self,n,a,w,g,t):
            student.__init__(self,n,a,w,g)
            speaker.__init__(self,n,t)
     
    test = sample("Tim",25,80,4,"Python")
    test.speak()   #方法名同,默认调用的是在括号中参数位置排前父类的方法
    
    • 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

    执行以上程序输出结果为:

    在这里插入图片描述

    方法重写

    如果你的父类方法的功能不能满足你的需求,你可以在子类重写你父类的方法,实例如下:

    class Parent:        # 定义父类
       def myMethod(self):
          print ('调用父类方法')
     
    class Child(Parent): # 定义子类
       def myMethod(self):
          print ('调用子类方法')
     
    c = Child()          # 子类实例
    c.myMethod()         # 子类调用重写方法
    super(Child,c).myMethod() #用子类对象调用父类已被覆盖的方法
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    super() 函数是用于调用父类(超类)的一个方法。

    执行以上程序输出结果为:

    在这里插入图片描述

  • 相关阅读:
    【FPGA】十进制计数器 | 实现 4-bit 2421 十进制计数器 | 有限状态机(FSM)
    《熟悉List集合》第一弹
    04、※NIO的理解、NIO的概念、缓冲区的读取数据、mark标志位置、reset回设的操作和通道文本数据获取与文本写出
    C4BUILDER—用于构建C4模型图的Web项目
    综述:大规模小目标检测
    C# 同步与异步方法
    KubeMeet 报名 | 「边缘原生」线上技术沙龙完整议程公布!
    Hive 使用达梦DM8 无法识别 “COMMENT” 问题
    020python-类与对象
    WPS Office for Linux即将面临开源
  • 原文地址:https://blog.csdn.net/qq_64973687/article/details/134027793