文章目录
面向对象编程(object-oriented programming,oop)是最有效的软件编写方法之一。
你编写表示现实世界中的事物和情景的类(class),并基于这些类来创建对象(object)。
编写类时,你定义一大类对象都有的通用行为。
根据类来创建对象称为实例化,这让你能够使用类的实例。
创建和使用类
编写一个表示小哥的简单类Dog,它表示的是任何小狗。
创建Dog类
Dog类表示的是任何小狗,因此它没有特定的小狗,而只是对小狗的抽象。
Dog类,每个实例都将储存名字和年龄,而且我们会赋予每条小狗坐下(sit())和打滚(rollover())的能力。
# 首先定义一个名为Dog的类,首字母大写名称是类
class Dog(object):
"""一次模拟小狗的简单尝试"""
# 类中的函数称为方法,__init__是一个特殊的方法,每当根据Dog类创建实例时,python都会自动运行它。
# 方法定义包含三个形参:self、name、age。
# 形参self必不可少,而且必须位于形参的前面。
def __init__(self, name, age):
"""初始化属性name和age"""
self.name = name
self.age = age
def sit(self):
"""模拟小狗收到命令时坐下"""
print(f"{self.name} is now sitting")
def roll_over(self):
"""模拟小狗收到命令时打滚"""
print(f"{self.name} rolled over")
类中的函数称为方法,__init__是一个特殊的方法,每当根据Dog类创建实例时,python都会自动运行它。
方法定义包含三个形参:self、name、age。
形参self必不可少,而且必须位于形参的前面。
_init_() 是一个特殊方法,每当你根据 Dog 类创建新实例时,Python 都会自动运行它。
开头和末尾各有两个下划线,这是一种约定,旨在避免 Python 默认方法与普通方法发生名称冲突。
Python 调用这个方法来创建 Dog 实例时,将自动传入实参 self。每个与实例相关联的方法调用都会自动传递实参 self,该实参是一个指向实例本身的引用,让实例能够访问类中的属性和方法。
根据类创建实例
# 我们让 Python 创建一条名字为 'Willie'、年龄为 6 的小狗
my_dog = Dog("Wille", 6)
# 使用提供的值设置属性 name 和 age。接下来,Python 返回一个表示这条小狗的实例,而我们将这个实例赋给变量 my_dog。
print(f"my_dog.name: {my_dog.name}")
print(f"my_dog.age: {my_dog.age}")
1.访问属性
要访问实例的属性,可使用句点表示法。
句点表示法是一种获取对象属性的方式。
# 访问实例的属性
print(f"my_dog.name: {my_dog.name}")
print(f"my_dog.age: {my_dog.age}")
2.调用方法
根据类创建实例后,就可以使用句点表示法来调用 Dog 类中定义的任何方法。
# 调用实例的方法
my_dog.sit()
my_dog.roll_over()
3.创建多个实例
可以根据一个类创建多个实例,就像可以根据 Dog 类创建任意数量的小狗。
# 根据类创建多个实例
your_dog = Dog("Lucy", 3)
print(f"your_dog.name: {your_dog.name}")
print(f"your_dog.age: {your_dog.age}")
your_dog.sit()
your_dog.roll_over()
使用类和实例
class Car:
"""一次模拟汽车的简单尝试"""
# 建新的 Car 实例时,需要指定其制造商、型号和生产年份。
def __init__(self, make, model, year):
"""初始化描述汽车的属性"""
self.make = make
self.model = model
self.year = year
def get_descriptive_name(self):
"""返回整洁的描述性信息"""
long_name = f"{self.year} {self.make} {self.model}"
return long_name.title()
my_new_car = Car("audi", "a4", 2019)
print(my_new_car.get_descriptive_name())
首先我们创建一个Car类,它表示汽车。
这个类有三个属性:make、model和year。
这个类还有一个方法:get_descriptive_name()。
这个方法返回一个整洁的描述性信息。
my_new_car = Car("audi", "a4", 2019)
print(my_new_car.get_descriptive_name())
我们创建了一个Car实例,并将其赋给变量my_new_car。
我们调用my_new_car的get_descriptive_name()方法,并将返回的值赋给变量long_name。
我们打印long_name的值。
给属性指定默认值
有些属性无须通过形参来定义,可以在 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 = f"{self.year} {self.make} {self.model}"
return long_name.title()
def read_odometer(self):
"""打印一条指出汽车里程的消息"""
print(f"This car has {self.odometer_reading} miles on it.")
我们在 init() 方法中为属性odometer_reading指定了默认值0。
这样,在创建Car实例时,这个属性就会自动设置为0。
my_new_car = Car("audi", "a4", 2019)
print(my_new_car.get_descriptive_name())
my_new_car.read_odometer()
我们创建了一个Car实例,并将其赋给变量my_new_car。
我们调用my_new_car的get_descriptive_name()方法,并将返回的值赋给变量long_name。
我们打印long_name的值。
我们调用my_new_car的read_odometer()方法,并打印出汽车的里程。
This car has 0 miles on it.
我们将odometer_reading的值设置为23,并再次调用read_odometer()方法。
my_new_car.odometer_reading = 23
my_new_car.read_odometer()
我们将odometer_reading的值设置为23,并再次调用read_odometer()方法。
This car has 23 miles on it.
修改属性的值
三种不同的方式修改属性的值:
- 直接修改属性的值
- 通过方法修改属性的值
- 通过方法对属性的值进行递增
1.直接修改属性的值
my_new_car = Car("audi", "a4", 2019)
print(my_new_car.get_descriptive_name())
my_new_car.odometer_reading = 23
my_new_car.read_odometer()
我们创建了一个Car实例,并将其赋给变量my_new_car。
我们调用my_new_car的get_descriptive_name()方法,并将返回的值赋给变量long_name。
我们打印long_name的值。
我们将odometer_reading的值设置为23,并再次调用read_odometer()方法。
This car has 23 miles on it.
2.通过方法修改属性的值
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 car has {self.odometer_reading} miles on it.")
def update_odometer(self, mileage):
"""将里程表读数设置为指定的值"""
self.odometer_reading = mileage
我们在Car类中添加了一个方法update_odometer(),它接受一个参数mileage,并将odometer_reading的值设置为mileage。
my_new_car = Car("audi", "a4", 2019)
print(my_new_car.get_descriptive_name())
my_new_car.update_odometer(23)
my_new_car.read_odometer()
我们创建了一个Car实例,并将其赋给变量my_new_car。
我们调用my_new_car的get_descriptive_name()方法,并将返回的值赋给变量long_name。
我们打印long_name的值。
我们调用my_new_car的update_odometer()方法,并将23作为参数传递给它。
我们调用my_new_car的read_odometer()方法,并打印出汽车的里程。
This car has 23 miles on it.
3.通过方法对属性的值进行递增
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 car has {self.odometer_reading} miles on it.")
def update_odometer(self, mileage):
"""将里程表读数设置为指定的值"""
self.odometer_reading = mileage
def increment_odometer(self, miles):
"""将里程表读数增加指定的量"""
self.odometer_reading += miles
我们在Car类中添加了一个方法increment_odometer(),它接受一个参数miles,并将odometer_reading的值增加miles。
my_new_car = Car("audi", "a4", 2019)
print(my_new_car.get_descriptive_name())
my_new_car.update_odometer(23)
my_new_car.read_odometer()
my_new_car.increment_odometer(100)
my_new_car.read_odometer()
我们创建了一个Car实例,并将其赋给变量my_new_car。
我们调用my_new_car的get_descriptive_name()方法,并将返回的值赋给变量long_name。
我们打印long_name的值。
我们调用my_new_car的update_odometer()方法,并将23作为参数传递给它。
我们调用my_new_car的read_odometer()方法,并打印出汽车的里程。
我们调用my_new_car的increment_odometer()方法,并将100作为参数传递给它。
我们调用my_new_car的read_odometer()方法,并打印出汽车的里程。
This car has 23 miles on it.
This car has 123 miles on it.
继承
继承是面向对象编程的一个重要概念,它允许你根据已有的类创建新类。
新类继承了已有类的属性和方法,同时可以添加新的属性和方法。
继承使得代码更加模块化,易于维护和扩展。
1.子类的方法__init__()
创建子类时,父类必须包含在当前文件中,且位于子类前面。
定义子类时,必须在括号内指定父类的名称。
方法__init__()接受创建 Car 实例所需的信息。
下面以创建电动汽车为例,我们将创建一个名为ElectricCar的子类,它继承了Car类。
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 car has {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)
我们创建了一个名为ElectricCar的子类,它继承了Car类。
我们在ElectricCar类中添加了一个方法__init__(),它接受一个参数make、model和year。
我们在ElectricCar类中添加了一个方法__init__(),它接受一个参数make、model和year。
my_tesla = ElectricCar("tesla", "model s", 2019)
print(my_tesla.get_descriptive_name())
我们创建了一个ElectricCar实例,并将其赋给变量my_tesla。
我们调用my_tesla的get_descriptive_name()方法,并将返回的值赋给变量long_name。
我们打印long_name的值。
2019 Tesla Model S
2.给子类定义属性和方法
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 car has {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 = 75
def describe_battery(self):
"""打印一条描述电瓶容量的消息"""
print(f"This car has a {self.battery_size}-kWh battery.")
我们创建了一个名为ElectricCar的子类,它继承了Car类。
我们在ElectricCar类中添加了一个属性battery_size,并将其值设置为75。
我们在ElectricCar类中添加了一个方法describe_battery(),它打印一条描述电瓶容量的消息。
my_tesla = ElectricCar("tesla", "model s", 2019)
print(my_tesla.get_descriptive_name())
my_tesla.describe_battery()
我们创建了一个ElectricCar实例,并将其赋给变量my_tesla。
我们调用my_tesla的get_descriptive_name()方法,并将返回的值赋给变量long_name。
我们打印long_name的值。
我们调用my_tesla的describe_battery()方法。
2019 Tesla Model S
This car has a 75-kWh battery.
重写父类中的方法
对于父类的方法,只要它不符合子类模拟的实物的行为,都可以对其进行重写。
为此,可在子类中定义一个这样的方法,即它与要重写的父类方法同名。
这样,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 = f"{self.year} {self.make} {self.model}"
return long_name.title()
def read_odometer(self):
"""打印一条指出汽车里程的消息"""
print(f"This car has {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 needs a gas tank!")
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.")
def fill_gas_tank(self):
"""电动汽车没有油箱"""
print("This car doesn't need a gas tank!")
我们创建了一个名为ElectricCar的子类,它继承了Car类。
我们在ElectricCar类中添加了一个方法fill_gas_tank(),它打印一条消息,指出电动汽车没有油箱。
my_tesla = ElectricCar("tesla", "model s", 2019)
my_tesla.fill_gas_tank()
我们创建了一个ElectricCar实例,并将其赋给变量my_tesla。
我们调用my_tesla的fill_gas_tank()方法。
2019 Tesla Model S
This car doesn't need a gas tank!
将实例用作属性
使用代码模拟实物时,你可能会发现自己给类添加的细节越来越多:属性和方法清单以及文件都越来越长。
在这种情况下,可能需要将类的一部分作为一个独立的类提取出来。
你可以将大型类拆分成多个协同工作的小类。
这种方法称为组合(composition)
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 car has {self.odometer_reading} miles on it.")
def update_odometer(self, mileage):
"""将里程表读数设置为指定的值"""
self.odometer_reading = mileage
def increment_odometer(self, miles):
"""将里程表读数增加指定的量"""
self.odometer_reading += miles
class Battery:
"""一次模拟电动汽车电瓶的简单尝试"""
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 = Battery()
my_tesla = ElectricCar("tesla", "model s", 2019)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
我们创建了一个名为Battery的类,它没有继承任何类。
我们在Battery类中添加了一个方法describe_battery(),它打印一条描述电瓶容量的消息。
我们在ElectricCar类中添加了一个属性battery,并将其值设置为Battery类的实例。
我们创建了一个ElectricCar实例,并将其赋给变量my_tesla。
我们调用my_tesla的get_descriptive_name()方法,并将返回的值赋给变量long_name。
我们打印long_name的值。
我们调用my_tesla的battery的describe_battery()方法。
2019 Tesla Model S
This car has a 75-kWh battery.
导入类
1.导入单个类
# 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 = f"{self.year} {self.make} {self.model}"
return long_name.title()
def read_odometer(self):
"""打印一条指出汽车里程的消息"""
print(f"This car has {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
我们创建了一个名为Car的类,它有一个方法get_descriptive_name(),它打印一条描述汽车的消息。
我们将这个类保存到一个名为car.py的文件中。
接下来创建另一个文件my_car.py,用于导入Car类并创建Car实例。
from car import Car
my_new_car = Car("audi", "a4", 2019)
print(my_new_car.get_descriptive_name())
my_new_car.odometer_reading = 23
my_new_car.read_odometer()
我们使用import语句导入Car类。
在一个模块中存储多个类
"""一组用于表示燃油汽车和电动汽车的类"""
class Car:
--snip--
class Battery:
"""一次模拟电动汽车电瓶的简单尝试"""
def __init__(self, battery_size=40):
"""初始化电池的属性"""
self.battery_size = battery_size
def describe_battery(self):
"""打印一条描述电池容量的消息"""
print(f"This car has a {self.battery_size}-kWh battery.")
def get_range(self):
"""打印一条描述电池续航里程的消息"""
if self.battery_size == 40:
range = 150
elif self.battery_size == 65:
range = 225
print(f"This car can go about {range} miles on a full charge.")
class ElectricCar(Car):
"""模拟电动汽车的独特之处"""
def __init__(self, make, model, year):
"""
先初始化父类的属性,再初始化电动汽车特有的属性
"""
super().__init__(make, model, year)
self.battery = Battery()
现在新建一个名为my_electric_car.py的文件,用于导入Car类和ElectricCar类,并创建ElectricCar实例。
from car import ElectricCar
my_tesla = ElectricCar("tesla", "model s", 2019)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
my_tesla.battery.get_range()
我们使用import语句导入ElectricCar类。
c从一个模块中导入多个类
from car import Car, ElectricCar
my_beetle = Car("volkswagen", "beetle", 2019)
print(my_beetle.get_descriptive_name())
my_tesla = ElectricCar("tesla", "roadster", 2019)
print(my_tesla.get_descriptive_name())
我们使用import语句导入Car类和ElectricCar类。
导入整个模块
import car
my_beetle = car.Car("volkswagen", "beetle", 2019)
print(my_beetle.get_descriptive_name())
my_tesla = car.ElectricCar("tesla", "roadster", 2019)
print(my_tesla.get_descriptive_name())
我们使用import语句导入整个car模块。
导入模块中的所有类
form module_name import *
这种导入方式不推荐使用,因为它可能导致命名冲突。
如果两个模块都包含一个名为Car的类,那么导入*时,Python将不知道要导入哪个Car类。
在一个模块中导入另一个模块
有时候,需要将类分散到多个模块中,以免模块太大或者在同一个模块中存储不相关的类。
现在可分别从每个模块中导入类。
from car import Car
from electric_car import ElectricCar
my_beetle = Car("volkswagen", "beetle", 2019)
print(my_beetle.get_descriptive_name())
my_tesla = ElectricCar("tesla", "roadster", 2019)
print(my_tesla.get_descriptive_name())
我们使用import语句导入Car类和ElectricCar类。
使用别名
from car import Car as C
from electric_car import ElectricCar as EC
找到合适的工作流
一开始应让代码结构尽量简单。首先尝试在一个文件中完成所有的工作,确定一切都能正确运行后,再将类移到独立的模块中。
Python标准库
Python 标准库是一组模块,在安装 Python 时已经包含在内。
Python 标准库包含了很多有用的模块,例如:
- os:用于操作文件和目录
- sys:用于操作 Python 解释器
- math:用于进行数学运算
- random:用于生成随机数
- datetime:用于处理日期和时间
- re:用于进行正则表达式匹配
- json:用于处理 JSON 数据
- csv:用于处理 CSV 数据
- pickle:用于序列化和反序列化 Python 对象
- unittest:用于编写和运行单元测试
- logging:用于记录日志
- argparse:用于解析命令行参数
- socket:用于进行网络编程
- threading:用于进行多线程编程
- multiprocessing:用于进行多进程编程
在这个模块中,一个有趣的函数是 randint()。
它接受两个参数:一个是下限,另一个是上限。
这个函数将返回一个位于指定范围内的随机整数。
import random
print(random.randint(1, 6))
我们导入了 random 模块,并使用 randint() 函数生成了一个 1 到 6 的随机整数。
3
在模块 random 中,另一个有趣的函数是 choice()。
它接受一个列表作为参数,并返回列表中的一个随机元素。
import random
players = ["charles", "martina", "michael", "florence", "eli"]
first_up = random.choice(players)
print(first_up)
我们导入了 random 模块,并使用 choice() 函数从 players 列表中选择了一个随机元素。
eli
类编码风格
类名
类名通常采用驼峰命名法,即每个单词的首字母大写,其余字母小写。
例如,类名可以是 Car、ElectricCar、Battery 等。
方法名
方法名通常采用小写字母和下划线的组合,例如 get_descriptive_name()、read_odometer()、update_odometer() 等。
属性名
属性名通常采用小写字母和下划线的组合,例如 make、model、year 等。
文档注释
对于每个类,都应在类定义后面紧跟一个文档字符串。这种文档字符串简要地描述类的功能。每个模块也都应包含一个文档字符串,对其中的类可用来做什么进行描述。
分隔
在类中,可以使用一个空行来分隔方法;而在模块中,可以使用两个空行来分隔类。
先编写导入标准库模块的 import 语句,再添加一个空行,然后编写导入你自己编写的模块的 import 语句。
往期
- Python3完全新手小白的学习手册 8 函数
- Python3完全新手小白的学习手册 7 用户输入和while循环
- Python3完全新手小白的学习手册 6 字典
- Python3完全新手小白的学习手册 5 if语句
- Python3完全新手小白的学习手册 4 操作列表
- Python3完全新手小白的学习手册 3 列表
- Python3完全新手小白的学习手册 2 变量和简单数据类型
- Python3完全新手小白的学习手册 1 Python 的安装

3万+

被折叠的 条评论
为什么被折叠?



