美文网首页
阅读《Python编程从入门到实践》Day10

阅读《Python编程从入门到实践》Day10

作者: 晓梅_aa3b | 来源:发表于2018-03-25 13:58 被阅读56次

    第九章(二)

    2、使用类和实例

    修改类的属性,可以直接修改实例的属性,也可以编写方法以特定的方式进行修改。

    (1)Car类

    下面是一个表示汽车的类,它存储了有关汽车的信息,还有一个汇总这些信息的方法:

    class Car():
        def __init__(self, make, model, year):
            self.make = make
            self.model = model
            self.year = year
        def get_descriptive_name(self):
            long_name = str(self.year) + ' ' + self.make + ' ' + self.model
            return long_name.title()
    
    my_new_car = Car('audi', 'a4', 2016)
    print(my_new_car.get_descriptive_name())
    # 输出:
    2016 Audi A4
    

    方法init()接受形参的值,并将它们存储在根据这个类创建的实例的属性中。创建新的Car实例时,我们需要指定其制造商、型号和生产年份。为了在方法get_descriptive_name()中访问属性的值,需要使用(self.属性名)。

    (2)给属性指定默认值

    类中的每个属性都必须有初始值,哪怕这个值是0或空字符串。在有些情况下,如设置默认值时,在方法init()内指定这种初始值是可行的;如果你对某个属性这样做了,就无需包含为它提供初始值的形参。

    class Car():
        def __init__(self, make, model, year):
            self.make = make
            self.model = model
            self.year = year
            self.odometer_reading = 0  # 1
        def get_descriptive_name(self):
            long_name = str(self.year) + ' ' + self.make + ' ' + self.model
            return long_name.title()
        def read_odometer(self):  # 2
            print("This car has " + str(self.odometer_reading) + " miles on it.")
    
    my_new_car = Car('audi', 'a4', 2016)
    print(my_new_car.get_descriptive_name())
    my_new_car.read_odometer()  # 3
    

    上述代码中的#号处是新增上去的,在第一个#号处Python将创建一个名为odometer_reading的属性,并将其初始值设置为0。在第二个#号处定义一个方法,用于打印汽车的里程数,并在第三个#号处调用该方法输出打印结果。

    (3)修改属性的值

    可以以三种不同的方式修改属性的值:直接通过实例进行修改;通过方法进行设置;通过方法进行递增(增加特定的值)。

    1. 直接修改属性的值
      要修改属性的值,最简单的方式就是通过实例直接访问它。
    my_new_car.odometer_reading = 23
    # 输出:
    2016 Audi A4
    This car has 23 miles on it.
    

    在调用read_odometer()方法前添加上面的语句,此语句通过句点表示法来直接访问并设置汽车的属性,这让该属性的值重新设置为23。

    1. 通过方法修改属性的值
      若有一个修改属性的方法,就无需直接访问属性,而可将值传递给一个方法,有它在内部进行更新。
    def update_odometer(self, mileage):
        self.odometer_reading = mileage
    my_new_car.update_odometer(23)
    # 输出:
    2016 Audi A4
    This car has 23 miles on it.
    

    在类中添加上述的方法,并在调用read_odometer()方法之前调用该方法对属性进行修改。最后的输出结果与上面直接访问属性的结果是一样的。
    还可以对update_odometer()进行扩展,比如禁止任何人将里程数往回调:

    def update_odometer(self, mileage):
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print("You can't roll back an odometer!")
    

    上述代码对update_odometer()方法进行修改。如果新指定的里程大于或等于原来的里程,就将里程表读数改为新指定的里程;否则就发出警告,指出不能将里程数往回调。

    1. 通过方法对属性的值进行递增
      有时候需要将属性值递增特定的量,而不是将其设置为全新的值。
    def increment_odometer(self, miles):
        self.odometer_reading += miles
    
    my_used_car = Car('subaru', 'outback', 2013)
    print(my_used_car.get_descriptive_name())
    my_used_car.update_odometer(23500)
    my_used_car.read_odometer()
    my_used_car.increment_odometer(100)
    my_used_car.read_odometer()
    # 输出:
    2013 Subaru Outback
    This car has 23500 miles on it.
    This car has 23600 miles on it.
    

    在类中新增一个方法increment_odometer(),用于将里程数递增一定的量。并将使用类和实例部分全部修改为第二部分的代码。从最后的输出结果可以看出,确实实现了增加100的效果。

    3、继承

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

    (1)子类的方法init()

    创建子类的实例时,Python首先需要完成的任务是给父类的所有属性赋值。
    下面模拟电动汽车,电动汽车是一中特殊的汽车,所以在Car类的基础上创建新类ElectricCar,这时只需要给电动汽车编写它独有的属性和方法。

    class ElectriCar(Car):
        def __init__(self, make, model, year):
            super().__init__(make, model, year)
    
    my_tesla = ElectriCar('tesla', 'model s', 2016)
    print(my_tesla.get_descriptive_name())
    # 输出:
    2016 Tesla Model S
    

    创建子类时,父类必须包含在当前文件中,且位于子类前面。定义子类时,必须在括号内指定父类的名称。方法init()接受创建Car实例所需的信息。super()是一个特殊的函数,帮助Python将父类和子类关联起来,让Python调用父类的方法,并让其包含父类的所有属性。父类也称为超类(superclass),名称super因此而得名。在这里,我们让子类调用父类的方法,由输出结果可以知道这样的继承是可行的。

    (2)Python 2.7中的继承

    在Python 2.7中,创建一个类时,括号内要写入object。函数super()需要两个实参:子类名和对象self,为帮助Python将父类与子类关联起来,这些实参必不可少。

    (3)给子类定义属性和方法

    让一个类继承另一个类后,可添加区分子类和父类所需的新属性和方法。下面添加一个电动汽车特有的属性(电瓶),以及一个描述该属性的方法。

    self.battery_size = 70
    
    def describe_battery(self):
        print("This car has a " + str(self.battery_size) + "-kWh battery.")
    
    my_tesla.describe_battery()
    # 输出:
    2016 Tesla Model S
    This car has a 70-kWh battery.
    

    init()方法中添加了新属性并设置初始值为70。根据ElectricCar类创建的所有实例都将包含这个属性,而所有Car实例都不包含它。在这里还添加了一个方法用于打印有关电瓶的信息。
    可根据需要的准确程度在子类中添加任意数量的属性和方法。如果一个属性或方法是任何汽车都有的,而不是电动汽车特有的,就应该将其加入父类而不是子类中。这样,使用父类的人将获得相应的功能,而子类只包含特有的属性和方法。

    (4)重写父类的方法

    对于父类的方法,只要它不符合子类模拟的实物的行为,都可对其进行重写。在子类中重写的方法必须与父类的方法同名。这样Python会忽略父类的方法,而执行子类中的方法。假设父类中有一个油箱的方法,但对电动汽车来说没有意义,因此可以对它进行重写。

    def fill_gas_tank():
        print("This car doesn't need a gas tank!")
    

    使用继承时,可让子类保留从父类那里继承而来的精华,并剔除不需要的糟粕。

    (5)将实例用作属性

    当给类添加的细节越来越多,属性和方法清单以及文件越来越长,就需要将类的一部分作为一个独立的类提取出来,可以将大型类拆分成多个协同工作的小类。如将关于电瓶的属性和方法提取出来放到一个名为Battery的类中,并将一个Battery实例用作ElectricCar类的一个属性:

    class Battery():
        def __init__(self, battery_size=70):
            self.battery_size = battery_size
        def describe_battery(self):
            print("This car has a " + str(self.battery_size) + "-kWh battery.")
    
    self.battery = Battery()
    
    my_tesla.battery.describe_battery()
    # 输出:
    2016 Tesla Model S
    This car has a 70-kWh battery.
    

    第一部分为定义的一个Battery新类,它没有继承任何类,在init()方法中给电瓶容量设置了初始值为70,这个形参是可选的。原来在电动汽车类中的方法也移到了这个类中。在ElectricCar类中添加了一个self.battery属性,每当方法init()被调用时,都将创建一个Battery实例,因此每个ElectricCar实例都包含一个自动创建的Battery实例。最后调用Battery类中的方法时,让Python在实例my_tesla中查找属性battery,并对存储在该属性中的Battery实例调用方法describe_battery()。

    (6)模拟实物

    当编写的程序能够很好的模拟实物时,就可以帮组你解决很多生活中的问题,可以收到意想不到的效果。

    相关文章

      网友评论

          本文标题:阅读《Python编程从入门到实践》Day10

          本文链接:https://www.haomeiwen.com/subject/jlehcftx.html