第9章 类 (Python编程:从入门到实践)

本文围绕Python类展开,介绍了创建类的方法,包括基本信息和行为的定义,以及特殊方法`__init__`的使用。还阐述了如何使用类创建实例,修改实例属性,以及类的继承、子类属性和方法的定义。此外,讲解了将实例用作属性和类的导入相关知识。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 创建类

使用类可以模拟任何东西
9.1.1 创建dog类为例子,表示的不是特定的小狗,是所有小狗。

  1. 9.1.1 创建dog类
class Dog():
    """A simple attempt to model a dog.一次模拟小狗的简单尝试"""
    def __init__(self, name, age):
        """Initialize name and age attributes.初始化属性name和age"""
        self.name = name
        self.age = age
    def sit(self):
        """Simulate a dog sitting in response to a command.模拟小狗被命令时蹲下"""
        print(self.name.title() + " is now sitting.")
    def roll_over(self):
        """Simulate rolling over in response to a command.模拟小狗被命令时打滚"""
        print(self.name.title() + " rolled over!")

将上面的代码拆分成两个部分,首先是基本信息,它们具备两项信息(名字和年龄)

    def __init__(self, name, age):
        """Initialize name and age attributes.初始化属性name和age"""
        self.name = name
        self.age = age

接着是行为(蹲下和打滚)

    def sit(self):
        """Simulate a dog sitting in response to a command.模拟小狗被命令时蹲下"""
        print(self.name.title() + " is now sitting.")
    def roll_over(self):
        """Simulate rolling over in response to a command.模拟小狗被命令时打滚"""
        print(self.name.title() + " rolled over!")

两串代码可以得到:根据Dog类创造的每个实例都会存储名字和年龄,以及蹲下和打滚两种能力

  1. 关于 方法__init__()

将方法__init__()拆成方法和__init__()来讲解

2.1 关于方法

类中的函数称为方法,函数的一切适用于方法
唯一差别是在于调用方法的方式,调用方法的方式我的理解就是方法是采用句点表示法,见后面。

2.2 关于__init__()
它是一个特殊的方法
第一点,根据XX类创建实例的时候,例如根据Dog类创建实例的时候my_dog = Dog(XXXX),会自动运行__init__()
第二点,开头和结尾各有__是为了和普通方法区别

2.3 以9.1.1 创建dog类作为例子讲解__init__()
9.1.1 创建dog类中,它有三个形参,分别是selfnameageself必不可少,并且在其他参数的前面。
Python调用__init__()创建Dog类实例的时候,会自动传入实参self。注意区别实参和形参(在第8章 函数有提及:形参是函数完成其工作所需的一项信息,实参是调用函数时传递给函数的信息)
每个与类相关联的方法调用会自动传递实参self,它是一个指向实例本身的引用,让实例能够访问类中的属性和方法。
创造Dog类实例的时候,Python调用Dog类的方法__init__(),通过实参向Dog()传递名字和年龄,self会自动传递,因此我们不需要传递,只需要给两个形参提供值。

  1. 我自己的理解:

(1) **创造实例my_dog的时候,编程输入my_dog=Dog('willie', 6)
之后Python内部调用__init__()创建Dog类的实例,自动传入实参selfmy_dog就是selfmy_dog会保存输入的两个参数(名字和年龄)

(2)接着当调用与类相关联的方法的时候,会自动传递实参self

(3)__init__()是一个指向实例本身的应用,可以访问类中的属性和方法

(4) 最后我们可以发现在9.1.1 创建dog类代码块中,两个变量nameage都有前缀self,也就是下面这几行代码

class Dog():
    """A simple attempt to model a dog.一次模拟小狗的简单尝试"""
    def __init__(self, name, age):
        """Initialize name and age attributes.初始化属性name和age"""
        self.name = name
        self.age = age

nameage是在创造实例的时候就输入,例如代码my_dog = Dog('willie', 6),根据代码含义这个时候就是把实参willie6实参存储到形参nameage上,
然后Python调用__init__()使用self.name = nameself.age = age获得存储在形参nameage的值,然后存储到变量nameage上,接着变量被关联到当前创建的实例。
自己认为的逻辑是先创造实例my_dog = Dog('willie', 6),其中实参willie6会因为__init__(self,name,age)存储到形参nameage上,接着根据代码

        self.name = name
        self.age = age

存储到self.nameself.age上,在P139中写到以self为前缀的变量都可供类中的所有方法使用,还可以通过类的任何实例来访问这些变量

  1. 补充说明

(1)根据约定,在Python中,首字母大写的名称是类。

(2)9.1.1 创建dog类的定义中的类的括号是空的,因为我们要从空白中去创造这个类,后面还有一个父类和子类的概念,那个时候就不是空白的了。

2 使用类

  1. 9.1.2 根据类创造实例
class Dog():
    """A simple attempt to model a dog.一次模拟小狗的简单尝试"""
    def __init__(self, name, age):
        """Initialize name and age attributes.初始化属性name和age"""
        self.name = name
        self.age = age
    def sit(self):
        """Simulate a dog sitting in response to a command.模拟小狗被命令时蹲下"""
        print(self.name.title() + " is now sitting.")
    def roll_over(self):
        """Simulate rolling over in response to a command.模拟小狗被命令时打滚"""
        print(self.name.title() + " rolled over!")
my_dog = Dog('willie', 6)

# 上面的这些是实例,直接运行是没有print的
# python使用实参'willie'和6调用Dog类的方法_init_()。
# 方法_init_()创建一个表示特定小狗的示例,并使用我们提供的值来设置属性name和age
# _init_()没有显式地包含return语句,但是python自动返回一个表示这条小狗的示例

'访问属性'
print("My dog's name is " + my_dog.name.title() + ".")
# My dog's name is Willie.
# 把属性name的值“willie”改成首字母大写的
print("My dog is " + str(my_dog.age) + " years old.")
# My dog is 6 years old.
# 把属性age的值6转换为字符串

'调用方法'
my_dog.sit()
# Willie is now sitting.
my_dog.roll_over()
# Willie rolled over!

'创建多个实例'
your_dog = Dog('lucy', 3)
print("\nMy dog's name is " + your_dog.name.title() + ".")
# My dog's name is Lucy.
print("My dog is " + str(your_dog.age) + " years old.")
# My dog is 3 years old.
your_dog.sit()
# Lucy is now sitting.
  1. 对上面9.1.2 根据类创造实例进行小结:

(1)一开始我的理解是创造类后(包括属性和方法),然后根据类创造实例my_dog = Dog('willie', 6),因为之前说过“会自动传递实参self”,我以为会自动运行,把sitroll_over运行,但是没有。随后仔细看发现是当调用与类相关联的方法的时候,会自动传递实参self,我一开始只是创造实例但是并没有调用与类相关的方法。

(2)关于调用类的方法和属性,前面提及到“ __init__()是一个指向实例本身的应用,可以访问类中的属性和方法”。

(3)源于P140:Python使用实参wille6调用Dog类中的方法__init__()。方法__init__()创造一个表示特定小狗的特例,并且使用我们所给的值设置属性nameage。方法__init__()没有显性地包含return语句,但是python会自动返回一个表示这条小狗的实例,这个实例会存储在变量my_dog中。

(4)一般首字母大写的是类,小写的是根据类创造的实例。

(5)访问实例的属性和方法,用句号表示法
例如

my_dog.name
my_dog.sit()

访问属性的操作看起来就像是先找到实例my_dog,然后再查找和这个实例相关的name。要注意,在Dog类中引用这个属性的时候,使用的是self.name。调用方法也是类似,指定实例的名称和调用的方法,并用句点分割它们。此处就是Python在类Dog中查找方法sit()并运行其代码。
句号表示法优点在于如果给属性和方法制定了合适的描述性名称,哪怕是从来没有见过的代码块,也可以推断它是什么作用。

(6)根据类创造任意数量的实例,条件是将每个实例都存储在不同的变量中,或占用列表或字典不同地方。

(7)调用一些方法不一定会输出print,还要看里面怎么写,如果是return就没有结果

3 使用类和实例

  1. 9.2.1 car类
    之前是以狗为例子,现在以车为例子
    这一章节主要是和属性有关。
"""A class that can be used to represent a car."""


class Car():
    """一次模拟汽车的简单尝试 A simple attempt to represent a car."""

    def __init__(self, make, model, year):
        """初始化描述汽车的属性 Initialize attributes to describe a car."""
        self.make = make
        self.model = model
        self.year = year


    def get_descriptive_name(self):
        """返回整洁的描述信息Return a neatly formatted descriptive name."""
        long_name = str(self.year) + ' ' + self.make + ' ' + self.model
        return long_name.title()

my_new_car = Car("audi","a4",2016)

my_new_car.get_descriptive_name()
# 什么也没有print,是因为用了return
print(my_new_car.get_descriptive_name())
# 2016 Audi A4
  1. 9.2.2 给属性指定默认值
"""A class that can be used to represent a car."""


class Car():
    """一次模拟汽车的简单尝试 A simple attempt to represent a car."""

    def __init__(self, make, model, year):
        """初始化描述汽车的属性 Initialize attributes to describe a car."""
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0

    def get_descriptive_name(self):
        """返回整洁的描述信息Return a neatly formatted descriptive name."""
        long_name = str(self.year) + ' ' + self.make + ' ' + self.model
        return long_name.title()

    def read_odometer(self):
        """打印出一条指出汽车里程的消息Print a statement showing the car's mileage."""
        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())
# 2016 Audi A4
my_new_car.read_odometer()
# This car has 0 miles on it.
# 前者要用print,后者不用。因为在设定方法的时候前者用了return,后者是print
  1. 9.2.3 修改属性的值(直接修改)
'直接修改属性的值'
"""A class that can be used to represent a car."""


class Car():
    """一次模拟汽车的简单尝试 A simple attempt to represent a car."""

    def __init__(self, make, model, year):
        """初始化描述汽车的属性 Initialize attributes to describe a car."""
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0

    def get_descriptive_name(self):
        """返回整洁的描述信息Return a neatly formatted descriptive name."""
        long_name = str(self.year) + ' ' + self.make + ' ' + self.model
        return long_name.title()

    def read_odometer(self):
        """打印出一条指出汽车里程的消息Print a statement showing the car's mileage."""
        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())
# 2016 Audi A4
my_new_car.read_odometer()
# This car has 0 miles on it.
# 前者要用print,后者不用。因为在设定方法的时候前者用了return,后者是print
my_new_car.odometer_reading = 23
# my_new_car.read_odometer = 23 这里我一开始用的是这个
# 但是这是函数,如果算下去是错的,'int' object is not callable
my_new_car.read_odometer()
# This car has 23 miles on it.
  1. 9.2.3 修改属性的值(通过方法)
'通过修改属性的值'
"""A class that can be used to represent a car."""


class Car():
    """一次模拟汽车的简单尝试 A simple attempt to represent a car."""

    def __init__(self, make, model, year):
        """初始化描述汽车的属性 Initialize attributes to describe a car."""
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0

    def get_descriptive_name(self):
        """返回整洁的描述信息Return a neatly formatted descriptive name."""
        long_name = str(self.year) + ' ' + self.make + ' ' + self.model
        return long_name.title()

    def read_odometer(self):
        """打印出一条指出汽车里程的消息Print a statement showing the car's mileage."""
        print("This car has " + str(self.odometer_reading) + " miles on it.")

    def update_odometer(self,mileage):
        self.odometer_reading = mileage

my_new_car = Car("audi","a4",2016)
print(my_new_car.get_descriptive_name())
# 2016 Audi A4
my_new_car.update_odometer(23)
my_new_car.read_odometer()
# This car has 23 miles on it.
  1. 9.2.3 修改属性的值(通过方法,禁止回调)
'通过方法修改属性的值'
"""A class that can be used to represent a car."""


class Car():
    """一次模拟汽车的简单尝试 A simple attempt to represent a car."""

    def __init__(self, make, model, year):
        """初始化描述汽车的属性 Initialize attributes to describe a car."""
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0

    def get_descriptive_name(self):
        """返回整洁的描述信息Return a neatly formatted descriptive name."""
        long_name = str(self.year) + ' ' + self.make + ' ' + self.model
        return long_name.title()

    def read_odometer(self):
        """打印出一条指出汽车里程的消息Print a statement showing the car's mileage."""
        print("This car has " + str(self.odometer_reading) + " miles on it.")

    def update_odometer(self,mileage):
        """
        Set the odometer reading to the given value.
        将里程碑指数设为指定的值
        Reject the change if it attempts to roll the odometer back.
        禁止里程碑往回调
        """
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print("You can't roll back an odometer!")

my_new_car = Car("audi","a4",2016)
print(my_new_car.get_descriptive_name())
# 2016 Audi A4
my_new_car.update_odometer(23)
my_new_car.read_odometer()
# This car has 23 miles on it.

my_new_car.update_odometer(10)
my_new_car.read_odometer()
# You can't roll back an odometer!
# This car has 23 miles on it.
# 这里禁止回调了,但是数值23还在,read_odometer函数也还是调用了
  1. 9.2.3 通过方法对属性的值进行递增
'通过方法修改属性的值'
"""A class that can be used to represent a car."""


class Car():
    """一次模拟汽车的简单尝试 A simple attempt to represent a car."""

    def __init__(self, make, model, year):
        """初始化描述汽车的属性 Initialize attributes to describe a car."""
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0

    def get_descriptive_name(self):
        """返回整洁的描述信息Return a neatly formatted descriptive name."""
        long_name = str(self.year) + ' ' + self.make + ' ' + self.model
        return long_name.title()

    def read_odometer(self):
        """打印出一条指出汽车里程的消息Print a statement showing the car's mileage."""
        print("This car has " + str(self.odometer_reading) + " miles on it.")

    def update_odometer(self,mileage):
        """
        Set the odometer reading to the given value.
        将里程碑指数设为指定的值
        Reject the change if it attempts to roll the odometer back.
        禁止里程碑往回调
        """
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print("You can't roll back an odometer!")

    def increment_odometer(self, miles):
        """将里程碑度数增加指定的量Add the given amount to the odometer reading."""
        self.odometer_reading += miles

my_used_car=Car("subaru","outback",2013)
print(my_used_car.get_descriptive_name())
# 2013 Subaru Outback

my_used_car.update_odometer(245)
my_used_car.read_odometer()
# This car has 245 miles on it.

my_used_car.increment_odometer(200)
my_used_car.read_odometer()
# This car has 445 miles on it.

对上面(从9.2.1 car类9.2.3 通过方法对属性的值进行递增)关于属性部分进行小结:

(1)类中的每个属性必须要有初始值,哪怕是0还是空字符串。
比如设置默认值,在方法__init__()指定默认值也是可以的,比如9.2.2 给属性指定默认值

    def update_odometer(self,mileage):
        self.odometer_reading = mileage

要注意,这里不像之前一样只有self了,而且还多了一个参数,一个我们想要去修改的参数odometer_reading,更新后再存储
此外我们还可以加入限制条件,例如9.2.3 修改属性的值(通过方法,禁止回调)

class Car():
    """一次模拟汽车的简单尝试 A simple attempt to represent a car."""

    def __init__(self, make, model, year):
        """初始化描述汽车的属性 Initialize attributes to describe a car."""
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0

其中的self.odometer_reading = 0就是默认参数。
此外如果对某个属性进行了这种操作,就无需提供初始值的形参了,比如my_new_car = Car("audi","a4",2016)

(2)接下来是关于属性的修改,分为三种方式:直接通过实例进行修改,通过方法进行设置,通过方法进行递增。
但是个人觉得第二种和第三种是一样的,其实都是方法。
首先说第一点,直接通过实例进行修改
例如代码9.2.3 修改属性的值(直接修改)其中的
my_new_car.update_odometer(23)就是在指定默认值后再次修改,是使用了句号表示法直接访问并设置汽车的属性odometer_reading,也就是Python在实例my_new_car中找到属性odometer_reading,然后把该属性值设置为23

第二点是关于方法的修改,如果设置了更新属性的方法,就不用直接访问属性,可以将值传递给一个方法,让它在内部进行更新。
比如9.2.3 修改属性的值(通过方法)其中的my_new_car.update_odometer(23)

class Car():
    """一次模拟汽车的简单尝试 A simple attempt to represent a car."""

    def __init__(self, make, model, year):
		跳过

    def get_descriptive_name(self):
        跳过

    def read_odometer(self):
        跳过

    def update_odometer(self,mileage):
        self.odometer_reading = mileage

my_new_car = Car("audi","a4",2016)
print(my_new_car.get_descriptive_name())
# 2016 Audi A4
my_new_car.update_odometer(23)
my_new_car.read_odometer()
# This car has 23 miles on it.

对于属性的直接修改和用方法修改分别是:
前者是 self.odometer_reading = 0然后my_new_car.odometer_reading = 23
再调用my_new_car.read_odometer()
而后者是方法update_odometer()

    def update_odometer(self,mileage):
        self.odometer_reading = mileage

然后再update_odometer(23)read_odometer()

my_new_car.update_odometer(23)
my_new_car.read_odometer()

先用方法update_odometer(23)更新(这里是有输入参数23的),再调用方法read_odometer()输出(这里就和之前对属性直接修改是一样的)

4 继承

  1. 9.3.1 子类的方法
    下面是在前面 9.2.1 car类的基础之上加了个class 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):
        """返回整洁的描述信息Return a neatly formatted descriptive name."""
        long_name = str(self.year) + ' ' + self.make + ' ' + self.model
        return long_name.title()

    def read_odometer(self):
        """打印出一条指出汽车里程的消息Print a statement showing the car's mileage."""
        print("This car has " + str(self.odometer_reading) + " miles on it.")

    def update_odometer(self,mileage):
        """
        Set the odometer reading to the given value.
        将里程碑指数设为指定的值
        Reject the change if it attempts to roll the odometer back.
        禁止里程碑往回调
        """
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print("You can't roll back an odometer!")

    def increment_odometer(self, miles):
        """将里程碑度数增加指定的量Add the given amount to the odometer reading."""
        self.odometer_reading += miles

class ElectricCar(Car):
    """电动汽车的独特之处"""
    def __init__(self,make,model,year):
        """初始化父类的属性"""
        super().__init__(make,model,year)

my_tesla = ElectricCar("tesla","model s",2016)
print(my_tesla.get_descriptive_name())
# 2016 Tesla Model S
my_tesla.read_odometer()
# This car has 0 miles on it.

(1)对于继承,在前面曾经提及到“9.1.1 创建dog类的定义中的类的括号是空的,因为我们要从空白中创造这个类”,编写类的时候不一定是总是从空白开始的,如果编写的类是另一个现成类(在前面写好了,且在同一个文档)的特殊版本,就可以继承。
一个类继承另一个类,会获得另一个类的所有属性和方法,原来的类叫做父类,新类叫做子类,子类不仅仅继承了父类的所有属性和方法,还可以创造自己的属性和方法

(2)创建子类的时候,父类必须在当前文件中,且位于子类的前面。定义子类的时候,必须在括号内指定父类的名称。__init__()接受创建Car实例所需的信息

(3)此外,来自P148,值得注意的是子类在继承父类的时候的写法,super()是把父类和子类联系起来的方法,调用父类的方法__init__()让子类继承父类所有的属性。
第一个__init__()需要接受创建父类实例所需要的信息
接着super()出现了,调用了子类中父类的方法__init__(),使得子类包含父类的全部属性。

class ElectricCar(Car):
    """电动汽车的独特之处"""
    def __init__(self,make,model,year):
        """初始化父类的属性"""
        super().__init__(make,model,year)

上面是创造子类,接着是给

5 子类属性和方法的定义

  1. 9.3.3 给子类定义属性和方法
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):
        """返回整洁的描述信息Return a neatly formatted descriptive name."""
        long_name = str(self.year) + ' ' + self.make + ' ' + self.model
        return long_name.title()

    def read_odometer(self):
        """打印出一条指出汽车里程的消息Print a statement showing the car's mileage."""
        print("This car has " + str(self.odometer_reading) + " miles on it.")

    def update_odometer(self,mileage):
        """
        Set the odometer reading to the given value.
        将里程碑指数设为指定的值
        Reject the change if it attempts to roll the odometer back.
        禁止里程碑往回调
        """
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print("You can't roll back an odometer!")

    def increment_odometer(self, miles):
        """将里程碑度数增加指定的量Add the given amount to the odometer reading."""
        self.odometer_reading += miles

class ElectricCar(Car):
    """电动汽车的独特之处"""
    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. ")

my_tesla = ElectricCar("tesla","model s",2016)
print(my_tesla.get_descriptive_name())
# 2016 Tesla Model S
my_tesla.read_odometer()
# This car has 0 miles on it.
my_tesla.describe_battery()
# This car has a 70-kwh battery.

一个类继承另一个类之后,就可以定义新的属性和方法了
可以在9.3.3 给子类定义属性和方法中看到:
多了个self.battery_size = 70,所有ElectricCar类的实例会有这个属性,但是在Car实例中没有

  1. 9.3.4 重写父类的方法(对比前)
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):
        """返回整洁的描述信息Return a neatly formatted descriptive name."""
        long_name = str(self.year) + ' ' + self.make + ' ' + self.model
        return long_name.title()

    def read_odometer(self):
        """打印出一条指出汽车里程的消息Print a statement showing the car's mileage."""
        print("This car has " + str(self.odometer_reading) + " miles on it.")

    def update_odometer(self,mileage):
        """
        Set the odometer reading to the given value.
        将里程碑指数设为指定的值
        Reject the change if it attempts to roll the odometer back.
        禁止里程碑往回调
        """
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print("You can't roll back an odometer!")

    def increment_odometer(self, miles):
        """将里程碑度数增加指定的量Add the given amount to the odometer reading."""
        self.odometer_reading += miles

    def fill_gas_tank(self):
        """为了和子类的fill_gas_tank函数形成对比"""
        print("我是父类")

class ElectricCar(Car):
    """电动汽车的独特之处"""
    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. ")

my_tesla = ElectricCar("tesla","model s",2016)
print(my_tesla.get_descriptive_name())
# 2016 Tesla Model S
my_tesla.fill_gas_tank()
# 我是父类

在子类中定义一个和父类方法同名的方法,Python就不会考虑这个父类方法,而是只关注在子类中定义的相应方法。
9.3.4 重写父类的方法(对比前)9.3.4 重写父类的方法(对比后)中可以得到体现。

  1. 9.3.4 重写父类的方法(对比后)
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):
        """返回整洁的描述信息Return a neatly formatted descriptive name."""
        long_name = str(self.year) + ' ' + self.make + ' ' + self.model
        return long_name.title()

    def read_odometer(self):
        """打印出一条指出汽车里程的消息Print a statement showing the car's mileage."""
        print("This car has " + str(self.odometer_reading) + " miles on it.")

    def update_odometer(self,mileage):
        """
        Set the odometer reading to the given value.
        将里程碑指数设为指定的值
        Reject the change if it attempts to roll the odometer back.
        禁止里程碑往回调
        """
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print("You can't roll back an odometer!")

    def increment_odometer(self, miles):
        """将里程碑度数增加指定的量Add the given amount to the odometer reading."""
        self.odometer_reading += miles

    def fill_gas_tank(self):
        """为了和子类的fill_gas_tank函数形成对比"""
        print("我是父类")

class ElectricCar(Car):
    """电动汽车的独特之处"""
    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. ")

    def fill_gas_tank(self):
        """为了和父类的fill_gas_tank函数形成对比"""
        print("This car doesn't need a gas tank!")

my_tesla = ElectricCar("tesla","model s",2016)
print(my_tesla.get_descriptive_name())
# 2016 Tesla Model S
my_tesla.fill_gas_tank()
# This car doesn't need a gas tank!

6 将实例用作属性

  1. 9.3.5 将实例用作属性(上)
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):
        """返回整洁的描述信息Return a neatly formatted descriptive name."""
        long_name = str(self.year) + ' ' + self.make + ' ' + self.model
        return long_name.title()

    def read_odometer(self):
        """打印出一条指出汽车里程的消息Print a statement showing the car's mileage."""
        print("This car has " + str(self.odometer_reading) + " miles on it.")

    def update_odometer(self,mileage):
        """
        Set the odometer reading to the given value.
        将里程碑指数设为指定的值
        Reject the change if it attempts to roll the odometer back.
        禁止里程碑往回调
        """
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print("You can't roll back an odometer!")

    def increment_odometer(self, miles):
        """将里程碑度数增加指定的量Add the given amount to the odometer reading."""
        self.odometer_reading += miles

    def fill_gas_tank(self):
        """为了和子类的fill_gas_tank函数形成对比"""
        print("我是父类")

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")
# Battery类没有继承任何类

class ElectricCar(Car):
    """电动汽车的独特之处"""
    def __init__(self,make,model,year):
        """初始化父类的属性,再初始化电动汽车特有的属性"""
        super().__init__(make,model,year)
        self.battery = Battery()
# 在ElectricCar类中,添加了一个叫做self.battery的属性
# 这行代码让Python创建了一个新的Battery实例
# 并且把这个实例值存储在属性self.battery中
# 每当__init__被调用,执行操作,每个ElectricCar实例包含一个自动创建的Battery实例

my_tesla = ElectricCar("tesla","model s",2016)

print(my_tesla.get_descriptive_name())
# 2016 Tesla Model S
my_tesla.battery.describe_battery()
# This car has a 70-kwh battery
  1. 9.3.5 将实例用作属性(下)
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):
        """返回整洁的描述信息Return a neatly formatted descriptive name."""
        long_name = str(self.year) + ' ' + self.make + ' ' + self.model
        return long_name.title()

    def read_odometer(self):
        """打印出一条指出汽车里程的消息Print a statement showing the car's mileage."""
        print("This car has " + str(self.odometer_reading) + " miles on it.")

    def update_odometer(self,mileage):
        """
        Set the odometer reading to the given value.
        将里程碑指数设为指定的值
        Reject the change if it attempts to roll the odometer back.
        禁止里程碑往回调
        """
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print("You can't roll back an odometer!")

    def increment_odometer(self, miles):
        """将里程碑度数增加指定的量Add the given amount to the odometer reading."""
        self.odometer_reading += miles

    def fill_gas_tank(self):
        """为了和子类的fill_gas_tank函数形成对比"""
        print("我是父类")

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")
# Battery类没有继承任何类
    def get_range(self):
        """打印出一条信息,指出电瓶的续航里程"""
        if self.battery_size == 70:
            range = 240
        elif self.battery_size == 85:
            range = 270
        message = "This car can go approximately " + str(range)
        message += " miles on a full charge"
        print(message)
class ElectricCar(Car):
    """电动汽车的独特之处"""
    def __init__(self,make,model,year):
        """初始化父类的属性,再初始化电动汽车特有的属性"""
        super().__init__(make,model,year)
        self.battery = Battery()
# 在ElectricCar类中,添加了一个叫做self.battery的属性
# 这行代码让Python创建了一个新的Battery实例
# 并且把这个实例值存储在属性self.battery中
# 每当__init__被调用,执行操作,每个ElectricCar实例包含一个自动创建的Battery实例

my_tesla = ElectricCar("tesla","model s",2016)

print(my_tesla.get_descriptive_name())
# 2016 Tesla Model S
my_tesla.battery.describe_battery()
# This car has a 70-kwh battery
my_tesla.battery.get_range()
# This car can go approximately 240 miles on a full charge

有的时候给类添加的细节越来越多:属性和方法越来越多
就需要把类的一部分作为一个独立的类提取出来,将大类拆分成多个协同工作的小类
比如把针对电瓶汽车属性和方法提取出来,于是在9.3.5 将实例用作属性(上)创建了Battery()

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")
# Battery类没有继承任何类

没有继承任何类,这是独立的一类是,是针对电瓶汽车属性和方法的一个类
此处可以看到Battery()在定义属性的时候,在__init__()的括号内不仅仅只有battery_size,而且还有battery_size=70,不像之前一样,只是

def __init__(self,battery_size):

或者

    def __init__(self,battery_size):
        """初始化电瓶的属性"""
        self.battery_size = battery_size

或者是

    def __init__(self):
        """初始化电瓶的属性"""
        self.battery_size = 70

这部分估计就是要联系到前面的函数了
之后

class ElectricCar(Car):
    """电动汽车的独特之处"""
    def __init__(self,make,model,year):
        """初始化父类的属性,再初始化电动汽车特有的属性"""
        super().__init__(make,model,year)
        self.battery = Battery()

出现了self.battery = Battery(),在super().__init__()之后
也就是将实例用作属性

self.属性名称=类

7 导入类

先编写两个car.pycartwo.py,等会来导入

  1. car.py
"""A class that can be used to represent a car."""


class Car():
    """A simple attempt to represent a car."""

    def __init__(self, manufacturer, model, year):
        """Initialize attributes to describe a car."""
        self.manufacturer = manufacturer
        self.model = model
        self.year = year
        self.odometer_reading = 0

    def get_descriptive_name(self):
        """Return a neatly formatted descriptive name."""
        long_name = str(self.year) + ' ' + self.manufacturer + ' ' + self.model
        return long_name.title()

    def read_odometer(self):
        """Print a statement showing the car's mileage."""
        print("This car has " + str(self.odometer_reading) + " miles on it.")

    def update_odometer(self, mileage):
        """
        Set the odometer reading to the given value.
        Reject the change if it attempts to roll the odometer back.
        """
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print("You can't roll back an odometer!")

    def increment_odometer(self, miles):
        """Add the given amount to the odometer reading."""
        self.odometer_reading += miles
  1. cartwo.py
"""A class that can be used to represent a car.一个可用于表示汽车的类"""


class Car():
    """A simple attempt to represent a car."""

    def __init__(self, manufacturer, model, year):
        """Initialize attributes to describe a car."""
        self.manufacturer = manufacturer
        self.model = model
        self.year = year
        self.odometer_reading = 0

    def get_descriptive_name(self):
        """Return a neatly formatted descriptive name."""
        long_name = str(self.year) + ' ' + self.manufacturer + ' ' + self.model
        return long_name.title()

    def read_odometer(self):
        """Print a statement showing the car's mileage."""
        print("This car has " + str(self.odometer_reading) + " miles on it.")

    def update_odometer(self, mileage):
        """
        Set the odometer reading to the given value.
        Reject the change if it attempts to roll the odometer back.
        """
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print("You can't roll back an odometer!")

    def increment_odometer(self, miles):
        """Add the given amount to the odometer reading."""
        self.odometer_reading += miles

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")
    def get_range(self):
        """打印出一条信息,指出电瓶的续航里程"""
        if self.battery_size == 70:
            range = 240
        elif self.battery_size == 85:
            range = 270
        message = "This car can go approximately " + str(range)
        message += " miles on a full charge"
        print(message)

class ElectricCar(Car):
    """电动汽车的独特之处"""
    def __init__(self,make,model,year):
        """初始化父类的属性,再初始化电动汽车特有的属性"""
        super().__init__(make,model,year)
        self.battery = Battery()
  1. 9.4.1 导入单个类 my_car
from car import Car
# 虽然是红色,不过还是可以运行的

my_new_car = Car("audi","a4",2016)
print(my_new_car.get_descriptive_name)
# <bound method Car.get_descriptive_name of <car.Car object at 0x00000238255DFC40>>
# 这里少了函数的括号

print(my_new_car.get_descriptive_name())
# 2016 Audi A4

my_new_car.odometer_reading = 23
my_new_car.read_odometer()
# This car has 23 miles on it.
  1. 9.4.2 在一个模块中存储多个类 my_electric_car
"""A set of classes that can be used to represent electric cars."""

from cartwo import ElectricCar

my_tesla = ElectricCar("tesla","model s",2016)
my_tesla.battery.describe_battery()
my_tesla.battery.get_range()
# This car has a 70-kwh battery
# This car can go approximately 240 miles on a full charge
  1. 9.4.3 在一个模块中导入多个类
from cartwo import Car,ElectricCar
# 导入了两个模块
my_beetle = Car("Volkswagen","beetle",2016)
print(my_beetle.get_descriptive_name())

my_tesla = ElectricCar("tesla","roadster",2016)
print(my_tesla.get_descriptive_name())

# 2016 Volkswagen Beetle
# 2016 Tesla Roadster

对上面的导入进行小结:
(1)导入:将类存储在模块中,然后再主程序中导入所需的模块

from 文件名 import 类

(2)import语句让Python打开模块car,到导入其中的Car
例如

from car import Car

(3)或者导入多个模块

from car import Car,ElectricCar

(4)从一个模块中导入多个类,用逗号分隔各个类
课外补充:"""XXX"""是文档字符串,描述这串代码是干嘛的

  1. 9.4.4 导入整个模块
import cartwo
my_beetle = cartwo.Car("volkswagen","beetle",2016)
print(my_beetle.get_descriptive_name())

my_tesla = cartwo.ElectricCar("tesla","roadster",2016)
print(my_tesla.get_descriptive_name())

# 2016 Volkswagen Beetle
# 2016 Tesla Roadster

导入整个模块,再用句点表示法访问需要的类

  1. 9.4.5 导入所有的类
from module_name import *

这个不推荐,写出来是因为防止看别人的代码的时候会有困惑。
使用这个可能会引发名称方面的困惑,如果不小心导入了一个与程序文件中其他东西同名的类就有问题
需要从一个模块中导入很多类的时候最好是导入整个模块,然后使用module_name.class_name语法访问类

  1. 9.4.6 在一个模块中导入另一个模块
    有的时候需要把类分散到多个模块,或者在一个模块中存储不相关的类
    electric_car
from car import Car
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")
    def get_range(self):
        """打印出一条信息,指出电瓶的续航里程"""
        if self.battery_size == 70:
            range = 240
        elif self.battery_size == 85:
            range = 270
        message = "This car can go approximately " + str(range)
        message += " miles on a full charge"
        print(message)

class ElectricCar(Car):
    """电动汽车的独特之处"""
    def __init__(self,make,model,year):
        """初始化父类的属性,再初始化电动汽车特有的属性"""
        super().__init__(make,model,year)
        self.battery = Battery()
  1. 9.4.6 在一个模块中导入另一个模块
from car import Car
from electric_car import ElectricCar
my_beetle = Car("volkswagen","beetle",2016)
print(my_beetle.get_descriptive_name())

my_tesla = ElectricCar("tesla","roadster",2016)
print(my_tesla.get_descriptive_name())
# 2016 Volkswagen Beetle
# 2016 Tesla Roadster

可以看到在electric_car中导入了一个模块,然后在9.4.6 在一个模块中导入另一个模块又导入了两个模块

Python编程:从入门到实践

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值