第 9 章 类
文章目录
9.1 创建和使用类
9.1.1 创建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!")
方法____________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 的作用与此类似。 像这样可通过实例访问的变量称为属性 。
9.1.2 根据类创建实例
class Dog():
--snip--
❶ 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.")
方法__init__() 并未显式地包含return 语句,
但Python自动返回一个表示这条小狗的实例。 我们将这个实例存储在变量my_dog 中。
要访问实例的属性, 可使用句点表示法。
my_dog.name
要调用方法, 可指定实例的名称(这里是my_dog ) 和要调用的方法, 并用句点分隔它们。
my_dog = Dog('willie', 6)
my_dog.sit()
my_dog.roll_over()
9.2.2 给属性指定默认值
如设置默认值时, 在方法__init__() 内指定这种初始值是可行的; 如果你对某个属性这样做
了, 就无需包含为它提供初始值的形参
class Car():
def __init__(self, make, model, year):
"""初始化描述汽车的属性"""
self.make = make
self.model = model
self.year = year
❶ self.odometer_reading = 0
9.2.3 修改属性的值
my_new_car.odometer_reading = 23
class Car():
--snip--
❶ def update_odometer(self, mileage):
"""将里程表读数设置为指定的值"""
self.odometer_reading = mileage
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
❷ my_new_car.update_odometer(23)
my_new_car.read_odometer()
9.3 继承
果你要编写的类是另一个现成类的特殊版本, 可使用继承 。 一个类继承 另一个类时, 它将自动获得另一个类的所有属性和方法; 原有的
类称为父类 , 而新类称为子类 。 子类继承了其父类的所有属性和方法, 同时还可以定义自己的属性和方法。
首先是Car 类的代码(见❶) 。 创建子类时, 父类必须包含在当前文件中, 且位于子类前面。
定义子类时, 必须在括号内指定父类的
名称。 方法init() 接受创建Car 实例所需的信息
class ElectricCar(Car):
"""电动汽车的独特之处"""
❸ def __init__(self, make, model, year):
"""初始化父类的属性"""
❹ super().__init__(make, model, year)
❺ my_tesla = ElectricCar('tesla', 'model
super() 是一个特殊函数, 帮助Python将父类和子类关联起来。 这行代码让Python调用ElectricCar 的父类的方法init() , 让ElectricCar 实例包含父类的所有属性。 父类也称为超类 (superclass) , 名称super因此而得名。
9.3.3 给子类定义属性和方法
super().__init__(make, model, year)
❶ self.battery_size = 70
❷ def describe_battery(self):
"""打印一条描述电瓶容量的消息"""
print("This car has a " + str(self.battery_size) + "-kWh battery.")
9.3.4 重写父类的方法
可在子类中定义一个这样的方法, 即它与要重写的父类方法同名。 这样, Python将不会考虑这
个父类方法, 而只关注你在子类中定义的相应方法。
9.3.5 将实例用作属性
9.4 导入类
9.4.1 导入单个类
from car import Car
"""从car.py中导入Car类"""
9.4.3 从一个模块中导入多个类
from car import Car, ElectricCar
9.4.4 导入整个模块
import car
此时需要用句点表示法访问需要的类
9.4.5 导入模块中的所有类
from module_name import *
不推荐使用这种导入方式, 其原因有二。 首先, 如果只要看一下文件开头的import 语句, 就能清楚地知道程序使用了哪些类, 将大有裨益; 但这种导入方式没有明确地指出你
使用了模块中的哪些类。 这种导入方式还可能引发名称方面的困惑。 如果你不小心导入了一个与程序文件中其他东西同名的类, 将引发难以诊断的错误。 这里之所以介绍这种导入方式, 是因为虽然不推荐使用这种方式, 但你可能会在别人编写的代码中见到它。
需要从一个模块中导入很多类时, 最好导入整个模块, 并使用 module_name.class_name 语法来访问类。 这样做时, 虽然文件开头并没有列出用到的所有类, 但你清楚地知道在程序的哪些地方使用了导入的模块; 你还避免了导入模块中的每个类可能引发的名称冲突。
9.4.6 在一个模块中导入另一个模块
例如, 下面将Car 类存储在一个模块中, 并将ElectricCar 和Battery 类存储在另一个模块中。 我们将第二个模块命名为electric_car.py (这将覆盖前面创建的文件
electric_car.py) , 并将Battery 和ElectricCar 类复制到这个模块中: electric_car.py
"""一组可用于表示电动汽车的类"""
❶ from car import Car
class Battery():
--snip--
class ElectricCar(Car):
--snip--
9.5 Python标准库
字典让你能够将信息关联起来, 但它们不记录你添加键—值对的顺序。 要创建字典并记录其中的键—值对的添加顺序, 可使用模块collections 中的OrderedDict
类。 OrderedDict 实例的行为几乎与字典相同, 区别只在于记录了键—值对的添加顺序。
❶ from collections import OrderedDict
❷ favorite_languages = OrderedDict()
请注意, 这里没有使用花括号, 而是调用OrderedDict() 来创建一个空的有序字典, 并将其存储在favorite_languages 中。
这是一个很不错的类, 它兼具列表和字典的主要优点(在将信息关联起来的同时保留原来的顺序)