Python基础知识点-- 类

    此文章为Python基础知识点(从入门到实践)--  类,此节Python基础知识点主要包括:创建和使用类、使用类和实例、继承、导入类、类编码风格。



       面向对象编程时是最有效的软件编写方法 之一,在面向对象编程中,我们编写表示现实世界中事务和情景的类,并基于这些类来创建对象。编写类时,我们定义一大类对象都有的通用行为。基于类创建对象时,每个对象都自动具备这种通用行为。根据类来创建对象称为实例化,这让我们能够使用类的实例。

一、创建和使用类

   使用类几乎可以模拟任何东西。下面1.1展示一个简单的例子:

1.1 创建 Dog 类

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

class Dog:
    """一次模拟小狗的简单尝试。"""

    def __init__(self,name,age):
        """初始化属性name和age。"""
        self.name = name #4
        self.age = age

    def sit(self):
        """模拟小狗收到命令时蹲下"""
        print(f'{self.name} is noe sitting.')

    def roll_over(self):
        '''模拟小狗收到命令时打滚'''
        print(f'{self.name} is rolled over!.')

       根据约定,在python中,首字母大写的名称指的是类。这个类定义中没有圆括号,因为要从空白创建这个类。第二行编写了一个文档字符串,对这个类的功能做了描述。

方法_init_()

      类中的函数称为方法。前面学到的有关函数的一切都适用于方法,唯一重要的差别是调用方法的方式。方法 _init_() 是个特殊方法,每当根据 Dog 类创建新实例时,Python都会自动运行它。在这个方法的名称中,开头和末尾各有两个下划线,这是一种约定,旨在避免python默认方法与普通方法发生名称冲突。务必确保 _init()_  的两边都有两个下划线,否则当使用类来创建实例时,将不会自动调用这个方法,进而引发难以发现的错误。

       我们将方法 _init()_ 定义成包含三个形参:self、name和age。在此方法中 self 必不可少,而且必须位于其他形参的前面。在python方法来创建Dog实例时将自动传递实参 self 。每个实例相关联的方法调用都自动传递实参self。它是一个指向实例本身的引用,让实例能够访问类中的属性和方法。

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

       Dog类还定义了两个另外方法:sit()和 roll_over() 。这些方法执行时不需要额外的信息,因此它们只有一个形参 self。随后将创建的实例能够访问这些方法,换句话说,他们都会蹲下和打滚。

1.2 根据类创建实例

       可将类视为有关如何创建实例的说明。Dog 类一系列说明,让python知道如何创建表示特定小狗的实例。

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

class Dog:
     --snip--

my_dog = Dog('Willie',7)

print(f"My dog's name is {my_dog.name}." ) #2
print(f"My dog is {my_dog.age} years old.") #3

       这里使用的是前一个示例中编写的 Dog 类。首先让 python 创建一条名字为”Willie“,年龄为‘7’的小狗的信息。遇到代码时,python使用实参‘Willie’和7调用Dog类的方法_init_()。方法_init_() 创建一个表示特定小狗的实例,而我们将这个实例赋给了变量 my_dog 。在这里,命名约定很有用:通常可认为首字母大写的名称(如Dog)指的是类,而小写的名称(如my_dog)指的是根据类创建的实例。

1. 访问属性

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

my_dog.name

      句点表示法在python中很常用,这种语法演示了python如何获悉属性的值。在这里,python先找到实例 my_dog ,再查找与该实例相关联的属性name。在Dog类中引用这个属性时,使用的是self.name。在3处,使用同样的方法来获取属性age的值。

输出是有关 my_dog 的摘要:

 2. 调用方法

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

class Dog:
     --snip--

my_dog = Dog('Willie',7)
my_dog.sit()
my_dog.roll_over()

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

Willie 按我们的命令做了:

 3. 创建多个实例

      可按照需求根据类创建任意数量的实例。下面再创建一个名为your_dog 的小狗实例:

class Dog:
     --snip--

my_dog = Dog('Willie',7)
your_dog = Dog('Lucy',2)

print(f"My dog's name is {my_dog.name}." ) 
print(f"My dog is {my_dog.age} years old.")
my_dog.sit()

print(f"Your dog's name is {your_dog.name}." ) 
print(f"Your dog is {your_dog.age} years old.")
your_dog.sit()

       在本例中创建了两条小狗,每条小狗都是一个独立的实例,有自己的一组属性,能够执行相同的操作:

       即使给第二条小狗指定同样的名字和年龄,python依然会根据Dog类创建另一个实例。我们可以按照需求根据一个类创建任意数量的实例,条件是将每个实例都存储在不同的变量中,或者占用列表或字典的不同位置。

二、使用类和实例

      可使用类来模拟现实世界的很多场景。类编写好后,,我们大部分时间将花在根据类创建的实例上。我们需要执行的一个重要任务是修改实例的属性。可以直接修改实例的属性,也可以以特定的方法进行修改。

2.1 Car类

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

class Car:
    """一次模拟汽车的简单尝试"""
    def __init__(self,make,model,year):  #1
        """初始化描述汽车的属性"""
        self.make = make
        self.model = model
        self.year = year

    def get_descriptive_name(self):   #2
        """返回需要的描述性信息."""
        long_name = f"{self.year} {self.make} {self.model}"
        return long_name.title()
my_new_car = Car('audi','a4',2015)  #3
print(my_new_car.get_descriptive_name())

       在1处定义了方法 _init_() 。与前面Dog 类中一样,这个方法的第一个形参为self。该方法还包含另外三个形参:make、model和year。方法 _init_() 接受这些形参的值,并将它们赋值给根据这个类创建的实例的属性。创建新的car实例时,需要制定其制造商、型号和生产年份。

       在2处定义了一个名为 get_descriptive_name() 的方法。在3处根据Car类创建了一个实例,并将其赋给变量my_new_car。

运行结果如下:

       为了让这个类更有趣,下面添加一个随时间变化的属性,用于存储汽车的总里程。

2.2 给属性指定默认值

       创建实例时,有些属性无需通过形参来定义,可在方法_init_()中为其指定默认值。

       下面添加一个名为 odometer_reading 的属性,其初始量总是为0.我们还添加了一个名为read_odometer()的方法,用于读取汽车的里程表:

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 = f"{self.year} {self.make} {self.model}"
        return long_name.title()

    def read_odometer(self):
        """打印一条指出汽车里程的消息"""
        print(f"This cars has {self.odometer_reading} miles on it.")

my_new_car = Car('audi','a4',2015)
print(my_new_car.get_descriptive_name())
my_new_car.read_odometer()

一开始汽车的里程为0:

 2.3 修改属性的值

       我们能以三种方式修改属性的值:直接通过实例进行修改、通过方法进行设置、通过方法进行递增(增加特定的值)。下面依次介绍这些方式:

1.直接修改属性的值 

      要修改属性的值,最简单的方式是通过实例直接访问它。下面代码直接将里程数设置成23:

class Car:
    --snip--

my_new_car = Car('audi','a4',2015)
print(my_new_car.get_descriptive_name())

my_new_car.odometer_reading =23
my_new_car.read_odometer()

输出结果:

     有时候需要像这样直接访问属性,但有时候需要编写对属性进行更新的方法。

2. 通过方法修改属性的值

      如果有方法能更新属性值就更好了,这样无需直接访问属性,而可将值传递给方法,由他在内部进行更新。下面演示了一个名为 uodate_odometer() 的方法:

class Car:
    --snip--

    def update_odometer(self,mileage):
        """将里程数设置成为特定的值"""
        self.odometer_reading = mileage


my_new_car = Car('audi','a4',2015)
print(my_new_car.get_descriptive_name())

my_new_car.update_odometer(28)
my_new_car.read_odometer()

输出结果如下:

3. 通过方法对属性值进行递增 

有时候将属性递增特定的量,而不是将其设置为全新的值。 例子如下:

class Car:
    --snip--

    def increment_odometer(self,mils):
        """将里程碑增加指定的量"""
        self.odometer_reading += mils


my_new_car = Car('audi','a4',2015)
print(my_new_car.get_descriptive_name())

my_new_car.update_odometer(28_500)
my_new_car.read_odometer()

my_new_car.increment_odometer(100)
my_new_car.read_odometer()

输出结果如下:

 三、继承

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

3.1 子类的方法 _init_()

       在既有类的基础上编写新类时,通常要调用父类的方法 _init_() 。这将初始化在父类 _init_() 方法中定义的所有属性,从而让子类包含这些属性。 

       例子如下:下面模拟电动汽车,因此可在前面创建的car类基础上创建新类 ElectricCar。这样就只需为电动汽车特有的属性和行为编写代码。

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 = f"{self.year} {self.make} {self.model}"
        return long_name.title()

    def read_odometer(self):
        """打印一条指出汽车里程的消息"""
        print(f"This cars has {self.odometer_reading} miles on it.")

    def update_odometer(self,mileage):
        """将里程数设置成为特定的值"""
        self.odometer_reading = mileage

    def increment_odometer(self,mils):
        """将里程碑增加指定的量"""
        self.odometer_reading += mils

class ElectricCar(Car):
    """电动汽车的独特之处"""

    def __init__(self,make,model,year):
        """初始化父亲的属性"""
        super().__init__(make,model,year)

my_tesla = ElectricCar('tesla','model s',2019)
print(my_tesla.get_descriptive_name())

       创建子类时,父类必须包含在当前文件中,并位于子类前面。定义子类时,必须在圆括号内指定父类的名称。方法 _init_() 接受创建 Car 实例所需的信息。

       super() 是一个特殊函数,让我们能够调用父类的方法。这行代码让python调用Car类的方法 _init_() ,让ElectricCar 实例包含这个方法中定义的所有属性。父类也称为超类(superclass),名称super 由此而来。

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

      ElectricCar 实例的行为与 Car 实例一样,现在可以开始定义电动汽车特有的属性和方法了。

3.2 给子类定义属性和方法

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

     下面来添加一个电动汽车特有的属性(电瓶):

class Car:
    --snip--


class ElectricCar(Car):
    """电动汽车的独特之处"""

    def __init__(self,make,model,year):
        """初始化父亲的属性"""
        super().__init__(make,model,year)
        self.battery_size = 75

    def describe_battery(self):
        """打印一条描述电瓶的信息"""
        print(f"This car has a {self.battery_size}-kwh battery.")

my_tesla = ElectricCar('tesla','model s',2019)
print(my_tesla.get_descriptive_name())
my_tesla.describe_battery()

输出结果如下:

 3.3 重写父类的方法

        对于父类的方法,只要它不符合子类模拟的实物的行为,都可以考虑重写。为此可在子类中定义一个与要重写的父类方法同名的方法。这样,python将不会考虑这个父类方法,而只关注你在子类中定义的相应方法。

       假设 Car 类有一个名为 fill_gas_tank()的方法,他对全电动汽车来说毫无意义,我们想重写他。下面演示一种重写方式:

class ElectricCar(Car):
    --snip--
    
    def fill_gas_tank(self):
    """电动汽车没有油箱"""
    print("This car doesn't need a gas tank!")

        现在如果有人对电动车调用方法 fill_gas_tank(),python将忽略 Car 类的方法,转而运行上述代码。使用继承时,可让子类保留从父类那里继承来的精华,并剔除不需要的糟粕。

3.4 将实例用作属性

       使用代码模拟实物时,可能会发现自己给类添加的细节越来越多:属性和方法清单以及文件都越来越长。在这种情况下,可能需要将类的一部分提取出来,作为一个独立的类。可将大类拆分成多个协同工作的小类。

例如,在不断给电瓶车类添加细节时,我们会发现包含很多针对汽车电瓶的属性和方法。在这种情况下,可将这些属性和方法提取出来,放到一个名为 Battery 的类中,并将一个 Battery 实例作为电瓶车类的属性:

class Car:
    --snip--

class Battry:
    """一次模拟电动汽车电瓶的简单尝试"""

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

    def describe_battery(self):
        """打印一条描述电瓶容量的消息。"""
        print(f"This car has a {self.battery_size}-kwh battery.")

class ElectricCar(Car):
    """电动汽车的独特之处"""

    def __init__(self,make,model,year):
        """初始化父亲的属性"""
        super().__init__(make,model,year)
        self.battery = Battry()



my_tesla = ElectricCar('tesla','model s',2019)

print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()

       我们定义了一个名为 Battery 的新类,他没有继承任何类。在 ElectricCar类中添加了一个名为 self.battery 的属性。这行代码让python创建了一个新的 Battery 实例,并将该实例赋给属性 self.battery。每当方法 _init_() 被调用时,都将执行该操作。因此现状每个  ElectricCar 实例都包含一个自动创建的 Battery 实例。

四、导入类

      随着不断给类添加功能,文件可能变得很长,即便使用继承亦如此。为遵守python的总体理念,应让文件尽可能整洁。python在这方面提供了帮助,允许将类存储在模块中,然后在主程序中导入需要的模块。

4.1 导入单个类

      下面来创建另一个文件,并导入之前的Car类:

from car import Car

      import 语句让python打开模块car并导入其中的Car类。

4.2 在一个模块中存储多个类

     虽然同一个模块中的类之间应存在某种相关性,但可根据需要在一个模块中存储任意数量的类。

4.3 从一个模块中导入多个类

    可根据需要在程序文件中导入任意数量的类。例子如下:

from car import Car,ElectricCar

      从一个模块导入多个类时,用逗号分隔了各个类。导入必要的类后,就可根据需要创建每个类的任意数量实例。

4.4 导入整个模块

      还可以导入整个类,再使用句点表示法访问需要的类。例子如下:

import car

my_li = car.Car()
my_hua = car.ElectricCar()

4.5 导入模块这的所有类(不太推荐)

from module_name import *

4.6 使用别名

from car import Car as C

4.7 类编码风格

       类名应采用驼峰命名法,即将类名中的每个单词都大写,而不使用下划线。实例名和模块名都采用小写格式,并在单词之间加上下划线。

      对于每个类,都应紧跟在类定义后面包含一个文档字符串。简要的描述类的功能,并遵守编写函数的文档字符串时采用的格式约定。每个模块也都应包含一个文档字符串,对其中类可用作什么进行描述。


今天的学习总结就到这里啦!如果有什么问题可以在评论区留言呀~

如果帮助到大家,可以一键三连+关注支持下~

参考学习书籍:Python编程 从入门到实践 (第二版)


系列文章目录

Python基础知识点-- 变量和简单数据类型

Python基础知识点-- 列表
Python基础知识点-- 遍历列表、切片、元组

Python基础知识点-- if 语句

Python基础知识点-- 字典

Python基础知识点-- 用户输入和while循环

Python基础知识点-- 函数

猜你喜欢

转载自blog.csdn.net/m0_57787115/article/details/129598486