Loading

9 第九章 类

创建和使用类

根据类来创建对象被称为实例化

# dog.py
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.")

# 调用方法
my_dog.sit()
my_dog.roll_over()

# 创建多个实例
my_dog = Dog('willie', 6)
your_dog = Dog('lucy', 3)

print("My dog's name is " + my_dog.name.title() + ".")
print("My dog is " + str(my_dog.age) + " years old.")
my_dog.sit()

print("\nYour dog's name is " + your_dog.name.title() + ".")
print("Your dog is " + str(your_dog.age) + " years old.")
your_dog.sit()

根据约定,在Python中,首字母大写的名称指的是类;
方法__init__() 并未显式地包含return 语句,但Python自动返回一个表示这条小狗的实例,之后将这个实例存储在 变量my_dog 中;
们常可以认为首字母大写的名称(如Dog )指的是类,而小写的名称(如my_dog )指的是根据类创建的实例;
如果给属性和方法指定了合适的描述性名称,如name 、age 、sit() 和roll_over(),即便是从未见过的代码块,我们也能够轻松地推断出它是做什么

使用类和实例

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

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

# 直接修改属性的值
my_new_car.odometer_reading = 23
my_new_car.read_odometer()

# 通过方法修改属性的值
my_new_car.update_odometer(64)
my_new_car.read_odometer()

# 通过方法对属性的值进行递增
my_used_car.increment_odometer(100)
my_used_car.read_odometer()

继承

# electric_car.py
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)
        self.battery_size = 70

    
    def describe_battery(self):
        """打印一条描述电瓶容量的消息"""
        print("This car has a " + str(self.battery_size) + "-kWh battery.")

    # 重写父类的方法:假设 Car 类有一个名为fill_gas_tank() 的方法
    def 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())
my_tesla.describe_battery()
# 使用代码模拟实物时,你可能会发现自己给类添加的细节越来越多:属性和方法清单以及文件都越来越长;  
# 在这种情况下,可能需要将类的一部分作为一个独立的类提取出来。你可以将大型类拆分成多个协同工作的小类。
class Car():
    --snip--

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

my_tesla = ElectricCar('tesla', 'model s', 2016)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
my_tesla.battery.get_range()

导入类

# 文件:car.py 包含了一个模块级文档字符串,对该模块的内容做了简要的描述
# 应为自己创建的每个模块都编写文档字符串
"""一个可用于表示汽车的类"""    

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
# 文件:my_car.py
from car import Car

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

my_new_car.odometer_reading = 23
my_new_car.read_odometer()

在一个模块中存储多个类

类Battery 和ElectricCar 都可帮助模拟汽车,因此下面将它们都加入模块car.py中

"""一组用于表示燃油汽车和电动汽车的类"""

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 Battery():
    """一次模拟电动汽车电瓶的简单尝试"""

    def __init__(self, battery_size=60):
        """初始化电瓶的属性"""
        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()
# 文件名:my_electric_car.py
from car import ElectricCar

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

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

从一个模块中导入多个类

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

导入模块中的所有类

from module_name import *

需要从一个模块中导入很多类时,最好导入整个模块,并使用 module_name.class_name 语法来访问类;
这样做时,虽然文件开头并没有列出用到的所有类,但你清楚地知
道在程序的哪些地方使用了导入的模块;
你还避免了导入模块中的每个类可能引发的名称冲突

从一个模块中导入另一个模块

# 文件:electric_car.py
"""一组可用于表示电动汽车的类"""

    from car import Car

    class Battery():
    --snip--

    class ElectricCar(Car):
    --snip--
# 文件:car.py
"""一个可用于表示汽车的类"""

class Car():
    --snip--
# 文件:my_cars.py
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())

自定义工作流程

一开始应让代码结构尽可能简单;
先尽可能在一个文件中完成所有的工作,确定一切都能正确运行后,再将类移到独立的模块中;
如果你喜欢模块和文件的交互方式,可在项目开始时就尝试将类存储到模块中;
先找出让你能够编写出可行代码的方式,再尝试让代码更为组织有序

Python标准库

Python标准库 是一组模块,安装的Python都包含它;
可使用标准库中的任何函数和类,只需在程序开头包含一条简单的import 语句

要创建字典并记录其中的键—值对的添加顺序,可使用模块collections 中的OrderedDict

# 文件:favorite_languages.py
from collections import OrderedDict

favorite_languages = OrderedDict()

favorite_languages['jen'] = 'python'
favorite_languages['sarah'] = 'c'
favorite_languages['edward'] = 'ruby'
favorite_languages['phil'] = 'python'

for name, language in favorite_languages.items():
    print(name.title() + "'s favorite language is " +
        language.title() + ".")

随着你对标准库的了解越来越深入,将熟悉大量可帮助你处理常见情形的模块;
你还可以从其他地方下载外部模块;
了解Python标准库

类编码风格

类名应采用驼峰命名法 ,即将类名中的每个单词的首字母都大写,而不使用下划线;
实例名和模块名都采用小写格式,并在单词之间加上下划线
对于每个类,都应紧跟在类定义后面包含一个文档字符串;
这种文档字符串简要地描述类的功能,并遵循编写函数的文档字符串时采用的格式约定;
每个模块也都应包含一个文档字符串,对其中的类可用于做什么进行描述

可使用空行来组织代码,但不要滥用;
在类中,可使用一个空行来分隔方法;
而在模块中,可使用两个空行来分隔类
需要同时导入标准库中的模块和你编写的模块时,先编写导入标准库模块的import 语句,再添加一个空行,然后编写导入你自己编写的模块的import 语句;
在包含多条import 语句的程序中,这种做法让人更容易明白程序使用的各个模块都来自何方

小结

如何编写类;
如何使用属性在类中存储信息,以及如何编写方法,以让类具备所需的行为;
如何编写方法__init__() ,以便根据类创建包含所需属性的实例;
如何修改实例的属性——包括直接修改以及通过方法进行修改;
使用继承可简化相关类的创建工作;
将一个类的实例用作另一个类的属性可让类更简洁;
通过将类存储在模块中,并在需要使用这些类的文件中导入它们,可让项目组织有序;
学习了Python标准库,并见识了一个使用模块collections 中的OrderedDict 类的示例;
最后,学习了编写类时应遵循的Python约定

posted @ 2023-04-19 23:38  Artwalker  阅读(14)  评论(0编辑  收藏  举报
Live2D