1. 创建和使用类
- 根据类来创建对象称为实例化
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!")
- Python中,首字母大写的名称指的是类,类定义中的括号里面是空的,比如上面的Dog()
- 类中的函数称为方法
- init() 是一个特殊的方法,每当根据Dog类创建实例时,程序都会自动运行它
- init(self,name,age) 定义包含了三个形参:self、name、age。其中的形参 self 必不可少,且必须位于其他形参的前面
- 通过实参向Dog()传递 name 和 age ,self 会自动传递,我们不需要传递它
- 每个与类相关联的方法调用都自动传递实参self,它是一个指向实例本身的引用,让实例能够访问类中的属性和方法
- 以self 为前缀的变量都可以供类中的所有方法使用
- self.name、self.age ,像这种可通过实例访问的变量称为属性
1.2 根据类创建实例
- 命名约定:
首字母大写的名称(如 Dog)指的是类
小写的名称(如 my_dog)指的是根据类创建的实例
1.2.1 访问属性
- 要访问实例的属性,可使用句点法
- 演示示例如下:
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.")
My dog's name is Willie.
My dog is 6 years old.
1.2.2 调用方法
- 要调用方法,可指定实例的名称(这里是 my_dog)和要调用的方法
- 演示示例如下:
class Dog():
--snip--
my_dog = Dog('willie',6)
my_dog.sit()
my_dog.roll_over()
Willie is now sitting.
Willie rolled over!
1.2.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()
my_dog.roll_over()
print("\nYour dog's name is " + your_dog.name.title() + ".")
print("Your dog is " + str(your_dog.age) + " years old.")
your_dog.sit()
your_dog.roll_over()
My dog's name is Willie.
My dog is 6 years old.
Willie is now sitting.
Willie rolled over!
Your dog's name is Lucy.
Your dog is 3 years old.
Lucy is now sitting.
Lucy rolled over!
2. 使用类和实例
- 类编写好之后,你的大部分时间都将花在使用根据类创建的实例上
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())
2016 Audi A4
2.2 给属性指定默认值
- 类中的每个属性都必须有初始值,哪怕这个值是0或空字符串
- 方法 init() 内指定这种初始值是可行的,如果对某个属性设置了默认值,则无需包含为它提供初始值的形参
- 演示示例如下:
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.")
my_new_car = Car('audi','a4',2016)
print(my_new_car.get_descriptive_name())
my_new_car.read_odometer()
2.3 修改属性的值
2.3.1 直接修改属性的值
- 要修改属性的值,最简单的方式就是通过实例直接访问它
- 演示示例如下:
class Car():
--snip--
my_new_car = Car2('audi','a4',2016)
print(my_new_car.get_descriptive_name())
my_new_car.odometer_reading = 23
my_new_car.read_odometer()
2016 Audi A4
This car has 23 miles on it.
2.3.2 通过方法修改属性的值
- 通过方法修改属性,无需直接访问属性,而是将值传递给一个方法,由它在内部更新
- 演示示例如下:
class Car():
--snip--
def update_odometer(self,mileage):
"""将里程表读数设置为指定的值"""
self.odometer_reading = mileage
my_new_car = Car3('audi','a4',2016)
print(my_new_car.get_descriptive_name())
my_new_car.update_odometer(23)
my_new_car.read_odometer()
2016 Audi A4
This car has 23 miles on it.
- 扩展演示示例如下:
class Car():
--snip--
def update_odometer(self,mileage):
"""
将里程表读数设置为指定的值
禁止将里程表读数往回调
"""
if mileage >= self.odometer_reading:
self.odometer_reading = mileage
else:
print("You can't roll back an odometer!")
my_new_car = Car4('audi','a4',2016)
print(my_new_car.get_descriptive_name())
my_new_car.update_odometer(23)
my_new_car.read_odometer()
2016 Audi A4
This car has 23 miles on it.
2.3.3 通过方法对属性的值进行递增
class Car():
--snip--
def update_odometer(self,mileage):
--snip--
def increment_odometer(self,miles):
""" 将里程表读数增加指定的量"""
self.odometer_reading += miles
my_used_car = Car5('subaru','outback',2013)
print(my_used_car.get_descriptive_name())
my_used_car.update_odometer(23500)
my_used_car.read_odometer()
my_used_car.increment_odometer(100)
my_used_car.read_odometer()
2013 Subaru Outback
This car has 23500 miles on it.
This car has 23600 miles on it.
3. 继承
- 一个类继承另一个类时,将自动获得另一个类的所有属性和方法;
- 原有的类称为父类(超类),新的类称为子类;
- 子类继承了父类的所有属性和方法,同时还可以定义自己的属性和方法
3.1 子类的方法 init()
- 演示示例如下:
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)
my_tesla = ElectricCar('tesla','model s',2016)
print(my_tesla.get_descriptive_name())
2016 Tesla Model S
- 创建子类时,父类必须包含在当前文件夹中,且位于子类前面。
- 定义子类时,必须在括号内指定父类的名称
- super()是一个特殊函数,帮助Python将父类和子类关联起来
3.2 给子类定义属性和方法
- 让一个类继承另一个类后,可添加区分子类和父类所需的新属性和方法
- 演示示例如下:
class Car():
--snip--
class ElectricCar1(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 = ElectricCar1('tesla','model s',2016)
print(my_tesla.get_descriptive_name())
my_tesla.describe_battery()
2016 Tesla Model S
This car has a 70-kwh battery.
3.3 重写父类的方法
- 对于父类方法,只要它不符合子类模拟实物的行为,可以对其进行重写
- 可在子类定义一个方法,它与要重写的父类方法同名,Python将不会考虑父类方法,而只关注你在子类定义的相应方法
- 使用继承时,可让子类保留从父类那里继承而来的精华,并剔除不需要的糟粕
- 演示示例如下:
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
def fill_gas_tank(self):
print("This car need a gas tank!")
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):
"""电动汽车没有油罐"""
print("This car does't need a gas tank!")
my_tesla = ElectricCar('tesla','model s',2016)
print(my_tesla.get_descriptive_name())
my_tesla.describe_battery()
my_tesla.fill_gas_tank()
2016 Tesla Model S
This car has a 70-kwh battery.
This car does't need a gas tank!
3.4 将实例用作属性
- 将类的一部分作为一个独立的类提取出来,将大型类拆分成多个协同工作的小类
- 演示示例如下:
class Car():
--snip--
class ElectricCar(Car):
"""电动汽车的独特之处"""
def __init__(self,make,model,year):
"""
初始化父类的属性,再初始化电动汽车特有的属性
"""
super().__init__(make,model,year)
self.battery= 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.")
my_tesla = ElectricCar('tesla','model s',2016)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
2016 Tesla Model S
This car has a 70-kwh battery.
3.扩展演示示例如下:
class Car():
--snip--
class ElectricCar(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)
my_tesla = ElectricCar4('tesla','model s',2016)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
my_tesla.battery.get_range()
2016 Tesla Model S
This car has a 70-kwh battery.
This car can go approximately 240 miles on a full charge.
4. 导入类
1.Python允许你将类存储在模块中,然后在主程序中导入所需的模块
4.1 导入单个类
1.演示示例如下:
car.py
"""一个可用于表示汽车的类"""
class Car():
"""一次模拟汽车的简单尝试"""
def __init__(self,make,model,year):
"""初始化描述汽车的属性"""
self.make = make
self.model = model
self.year = year
self.odometer_reading = 100
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()
2016 Audi A4
This car has 23 miles on it.
4.2 在一个模块中存储多个类
1.可根据需要在一个模块中存储任意数量的类
2. 类Battery和类ElectricCar都可帮助模拟类,可将其加入模块car.py中
3. 演示示例如下:
car.py
"""一组用于表示燃油汽车和电动汽车的类"""
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_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()
2016 Tesla Model S
This car has a 70-kwh battery.
This car can go approximately 240 miles on a full charge.
4.3 在一个模块中导入多个类
- 从一个模块中导入多个类时,用逗号分隔各个类
- 演示示例如下:
my_cars.py
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())
2016 Volkswagen Beetle
2016 Tesla Roadster
4.4 导入整个模块
- 可以导入整个模块,再使用句点表示法访问需要的类
- 由于创建类实例的代码都包含模块名,不会与当前文件使用的任何名称发生冲突
- 演示示例如下:
my_cars.py
import car
my_beetle =car.Car('volkswagen','beetle',2016)
print(my_beetle.get_descriptive_name())
my_tesla = car.ElectricCar('tesla','roadster',2016)
print(my_tesla.get_descriptive_name())
4.5 导入模块中的所有类
- from module_name import *
- 不推荐使用这种导入方式
- 需要从一个模块导入很多类时,最好导入整个模块,并使用module_name.class_name语法来访问类
4.6 在一个模块中导入另一个模块
- 当一个模块中的类太大,可将类分散到多个模块中
- 将类存储在多个模块中,当出现一个模块中的类需要依赖于另一个模块中的类才能实现功能时,可在前一个模块中导入必要的类
- 演示示例如下:
car.py
"""一个可用于表示汽车的类"""
class Car():
--snip--
electric_car.py
"""一组可用于表示电动汽车的类"""
from car import Car
class Battery():
--snip--
class ElectricCar(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())
2016 Volkswagen Beetle
2016 Tesla Roadster
4.7 自定义工作流程
- 一开始应让代码结构尽可能简单。先尽可能在一个文件中完成所有工作,确定一切都能正确运行后,再将类移到独立的模块中
- 如果你喜欢模块和文件的交互方式,可在项目开始时就尝试将类存储到模块中
- 先找出让你能够编写出可行代码的方式,再尝试让代码更为组织有序
5. Python标准库
- 字典让你能够将信息关联起来,但不记录你添加键—值对的顺序
- 模块collections中的OrdereDict类可实现记录键—值对的添加顺序
- 演示示例如下:
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() + ".")
Jen's favorite language is Python.
Sarah's favorite language is C.
Edward's favorite language is Ruby.
Phil's favorite language is Python.
6. 类编码风格
- 类名应采用驼峰命名法,即将类中的每个单词的首字母都大写,而不使用下划线
- 实例名和模块名都采用小写格式,并在单词之间加上下划线
- 对于每个类,都应紧跟在类定义后面包含一个文档字符串
- 每个 模块也都应包含一个文档字符串
- 在类中,可使用一个空行来分隔方法;在模块中,可使用两个空行来分隔类
- 需要同时导入标准库中的模块和你编写的模块时,先编写导入标准库模块的import语句,再添加一个空行,然后编写导入你自己编写的import语句