第九章 类
面向对象编程;你定义一大类对象都有的通用行为。基于类创建对象时,每个对象都自动具备这种通用行为,然后可根据需要赋予每个对象独特的个性。
根据类来创建对象被称为实例化。你将指定可在实例中存储什么信息,定义可对这些实例执行哪些操作。你还将编写一些类来扩展既有类的功能,让相似的类能够高效地共享代码。
9.1 创建和使用类
创建简单的Dog类(表示任何小狗),创建表示小狗的对象,将创建表示特定小狗的实例。
9.1.1 创建Dog类
在Python中,首字母大写的名称指的是类。这个类定义中的括号是空的,因为我们要从空白创建这个类。
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! ")
类中的函数称为方法,前面所有的跟函数有关的一切都适用于方法。
1、 -init-()方法是一个特殊的方法,在根据Dog类创建新实例的时候,python都会自动运行它。 我们将方法__init__()定义成了包含三个形参:self、name和age。在这个方法的定义中,形参self必不可少,还必须位于其他形参的前面。它是一个指向实例本身的引用。让实例能够访问类中的属性和方法。
以self为前缀的变量都可供类中的所有方法使用。self.name等。
像这样可通过实例访问的变量称为属性。
2、在python2.7中创建类
在Python 2.7中创建类时,需要做细微的修改——在括号内包含单词object:
class ClassName(object):
--snip--
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__()创建一个表示特定小狗的示例,并使用我们提供的值来设置属性name和age。方法__init__()并未显式地包含return语句,但Python自动返回一个表示这条小狗的实例。并且一般大写的名称指的都是类,小写的才是指根据类创建的实例。
1、 访问属性
my_dog.name 句点表示法。python先找到实例my_dog,然后再查找与这个实例相关联的属性name,在Dog类中引用这个属性时,使用的是self.name。。。。
2、调用方法
#调用方法
class Dog():
--snip--
my_dog = Dog('Willie', 6)
my_dog.sit()
my_dog.roll_over()
3、创建多个实例
可以按照需求根据类创建任意数量的实例。你可按需求根据一个类创建任意数量的实例,条件是将每个实例都存储在不同的变量中,或占用列表或字典的不同位置。
# class Dog():
# --snip--
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 ols. ")
your_dog.sit()
9.2 使用类和实例
你需要执行的一个重要任务是修改实例的属性。你可以直接修改实例的属性,也可以编写方法以特定的方式进行修改。
9.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())
9.2.2 给属性指定默认值
类中的每个属性都必须有初始值,就算这个值是0或者空字符串也行。
在方法__init__()内指定这种初始值是可行的;如果你对某个属性这样做了,就无需包含
为它提供初始值的形参。
9.2.3 修改属性的值
可以以三种不同的方式修改属性的值:直接通过实例进行修改;通过方法进行设置;通过方法进行递增(增加特定的值)。
1、直接修改属性的值
通过实例直接访问它。。
# 设置默认值,,,通过实例直接访问它修改属性的值。。
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
my_new_car.odometer_reading = 23
2、通过方法修改属性的值
编写对属性进行更新的方法。无需直接访问属性,可将值传递给一个方法,由它在内部进行更新。。
3、通过方法对属性的值进行递增
有时候需要将属性值递增特定的量,而不是将其设置为全新的值。
你可以轻松地修改这个方法,以禁止增量为负值,从而防止有人利用它来回拨里程表。
9.3 继承
如果你要编写的类是另一个现成类的特殊版本,可使用**继承。**一个类继承另一个类时,它将自动获得另一个类的所有属性和方法;原有的类称为父类,新类称为子类。子类继承了其父类的所有属性和方法,同时还可以定义自己的属性和方法。
9.3.1 子类的方法__init__()
创建子类的实例时,Python首先需要完成的任务是给父类的所有属性赋值。
class Car():
--snip--
除了方法__init__()之外,电动汽车没有其他特有的属性和方法。
创建子类时,父类必须包含在当前文件中,且位于子类前面。
super()是一个特殊函数
,帮助Python将父类和子类关联起来。父类也称为超类。
9.3.2 Python2.7中的继承
函数supeer()需要两个实参:子类名和对象self。在Python 2.7中使用继承时,务必在定义父类时在括号内指定object。
9.3.3 给子类定义属性和方法
让一个类继承另一个类后,可添加区分子类和父类所需的新属性和方法。
使用Car类的人将获得相应的功能,而ElectricCar类只包含处理电动汽车特有属性和行为的代码。
9.3.4 重写父类的方法
对于父类的方法,只要它不符合子类模拟的实物的行为,都可对其进行重写。
在子类中定义一个这样的方法,即它与要重写的父类方法同名。
现在,如果有人对电动汽车调用方法fill_gas_tank(),Python将忽略Car类中的方法fill_gas_tank(),转而运行上述代码。使用继承时,可让子类保留从父类那里继承而来的精华,并剔除不需要的糟粕。
9.3.5 将实例用作属性
在这种情况下,可能需要将类的一部分作为一个独立的类提取出来。你可以将大型类拆分成多个协同工作的小类。
self.battery = Battery(),这行代码让python创建一个新的Battery实例,每次__init__()被调用的时候,都执行该操作,因此现在每个ElectricCar实例都包含一个自动创建的Battery实例。
9.3.6 模拟实物
9.4 导入类
Python允许你将类存储在模块中,然后在主程序中导入所需的模块。
9.4.1 导入单个类
在car1.py中定义整个类Car的属性及方法,在my_car.py中导入类Car。
from car1 import Car #打开模板car1,并导入其中的Car类
my_new_car = Car('adui', 'a4', 2016)
print(my_new_car.get_descriptive_name())
my_new_car.odometer_reading = 23
my_new_car.read_odometer()
9.4.2 在一个模板中存储多个类
虽然同一个模块中的类之间应存在某种相关性,但可根据需要在一个模块中存储任意数量的类。
在car1.py中定义整个类Car的属性及方法,类ElectricCar继承了类Car,在my_electric_car.py中导入类ElectricCar。
from car1 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()
9.4.3 从一个模块中导入多个类
## 9.4.3 在一个模块中导入多个类,可在程序文件中导入任意数量的类。。。
from car1 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())
从一个模块中导入多个类是,用逗号分隔了各个类。
9.4.4 导入整个模块
#9.4.4 导入整个模块
import car1
my_beetle = car1.Car('volkswagen', 'beetle', 2016)
print(my_beetle.get_descriptive_name())
my_tesla = car1.ElectricCar('tesla', 'roadster', 2016)
print(my_tesla.get_descriptive_name())
我们导入了整个car模块,使用语法module_name.class_name访问需要的类。
9.4.5 导入模块中的所有类
from module_name import ,但是不推荐。
需要从一个模块中导入很多类时,最好导入整个模块,并使用module_name.class_name语法来访问类。
9.4.6 在一个模块中导入另一个模块
9.4.7 自定义工作流程
开始应让代码结构尽可能简单。先尽可能在一个文件中完成所有的工作,确定一切都能正确运行后,再将类移到独立的模块中。
要了解Python标准库,可以查看Python Module of the Week,或者访问http://pymotw.com/并查看其中的目录。。。。
9.6 类编码风格
类名用驼峰命名法,类名中的每个单词的首字母大写,不使用下划线。
实例和模块名都使用小写格式,并在单词之间加上下划线。
类定义后面包含一个文档字符串,这个文档字符串简要地描述类的功能。每个模块也应该包含。
在类中,使用一个空行来分隔方法;模块中使用两个空行来分隔类。
需要同时导入标准库中的模块和你编写的模块时,先编写导入标准库模块的import语句,再
添加一个空行,然后编写导入你自己编写的模块的import语句。