本文章是对学习python类的内容进行的简单总结
类
面向对象编程是最有效的软件编写方法之一。在面向对象编程中,我们编写表示现实世界中事务和情景的类,并基于这些类创建。
根据类来创建对象被称为实例化,这让我们能使用类的实例。
1.1 创建和使用类
下面我们来具体创建一些类来演示
1.1.1 创建Dog类
根据Dog类创建的每个实例都将存储名字和年龄。我们赋予了每条小狗蹲下(sit())和打滚(roll——over())的能力。
class Dog():def __init__(self,name,age):self.name=nameself.age=agedef sit(self):#模拟小狗被命令时蹲下print(self.name.title() +\"is now sitting.\")def roll_over(self):#模拟小狗被命令时打滚print(self.name.title()+\"rolled over!\")
根据约定,在Python中,首字母大写的名称指的是类,这个类定义中的括号是空的,因为我们要从空白创建这个类。
方法_init_:
类中的函数称为方法;_ init_()方法是一个特殊方法,每当我们根据Dog类创建实例时,python都会自动运行它。
在上面例子中我们将方法_init_()定义成包含三个形参:self,name,age。在这个方法的定义中,形参self必不可少,而且要位于其他形参之前,这是因为python调用这个_init_()方法创建实例时,将自动传入实参self。每个与类相关联的方法调用都自动传递实参self,它是一个指向实例本身的引用,让实例能访问类中属性和方法。
我们创建Dog实例时,python将调用Dog类的方法_init_()。我们将通过实参向Dog()传递名字和年龄;self会自动传递,因此我们不需要传递它。
Dog类还定义了另外两个方法:sit()和roll_over()。由于这些方法不需要额外的信息,如名字和年龄,因此它们只有一个形参self。
1.1.2 根据类创建实例
可将类视为有关如何创建实例的说明。Dog类是一系列说明,让Python知道如何创建表示特定小狗的实例。下面来创建一个表示特定小狗的实例:
class Dog():def __init__(self,name,age):self.name=nameself.age=agedef 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)+\"year old.\")####My dog\'s name isWillie.My dog is 6 year old.
这里使用的是之前编写的Dog类,我们创建一条名字为 ‘wille’ ,年龄为6的小狗。遇到这行代码时,python使用实参 ‘wille’ 和 6调用Dog类中的方法 _ init_()。方法_ init_()创建一个表示特定小狗的实例,并使用我们提供的值来设置属性name和age。方法_ init_()并未显示的包含return语句,但python自动返回一个表示这条小狗的的实例。我们将这个实例存储在变量my_dog中。
调用方法
my_dog.sit()my_dog.roll_over()####Willieis now sitting.Willierolled 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)+\" year 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 isWillie.My dog is 6 year old.Willieis now sitting.Willierolled over!Your dog\'s name is Lucy.Your dog is 3years old.Lucyis now sitting.Lucyrolled over!
在这里我们创建了两条小狗,分别命名为willie和lucy。每条小狗都是一个独立的实例,有自己的一组属性。
使用类和实例
我们可以用类来模拟现实世界中的很多情景。类编写好后,我们的大部分时间都将花费在类创建的实例上。我们需要执行的一个重要任务是修改实例的属性。我们可以直接修改实例的属性,也可以编写方法以特定的方式进行修改。
2.1.1 Car 类
下面来编写一个汽车类,它存储了有关汽车的信息,还有一个汇总这些信息的方法:
class Car():def __init__(self,make,model,year):self.make=makeself.model=modelself.year=yeardef get_descriptive_name(self):long_name=str(self.year)+\' \'+self.make+\' \'+self.modelreturn long_name.title()my_new_car=Car(\'audi\',\'a4\',2016)print(my_new_car.get_descriptive_name())####2016 Audi A4
2.1.2 给属性指定默认值
类中的每个属性都必须有初始值,哪怕这个值是零或者空字符。在有些情况下,如果设置默认值时,在方法_init_()内指定这种初始值是可行的。如果我们对某个属性这样做了,就无须包含为它提供初始值的形参。
class Car():def __init__(self,make,model,year):self.make=makeself.model=modelself.year=yearself.odometer_reading=0def get_descriptive_name(self):long_name=str(self.year)+\' \'+self.make+\' \'+self.modelreturn 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()####2016 Audi A4This car has 0 miles on it.
上面程序中添加了一个名为odometer_reading的属性,其初始值总是为0.我们还添加了一个名为read_odometer()方法,用于读取汽车的里程表。
2.1.3 修改属性的值
可以以三种不同的方式修改属性的值:直接通过实例进行修改;通过方法进行设置;通过方法进行设置;通过方法进行递增(增加特定的值)。
1.直接修改属性的值
my_new_car.odometer_reading=23my_new_car.read_odometer()####This car has 23 miles on it.
2.通过方法修改属性的值
class Car():--snip--def update_odometer(self,mileage):if mileage >=self.odometer_reading:self.odometer_reading=mileageelse:print(\"You can\'t roll back an odometer!\")
我们新增的update_odometer()会在修改属性前检查指定的读书是否合理。
3.通过方法对属性的值进行递增
class Car():--snip--def update_odometer(self,mileage):--snip--def increment_odometer(self,miles):self.odometer_reading += milesmy_new_car=Car(\'subaru\',\'outback\',2013)print(my_new_car.get_descriptive_name())my_new_car.update_odometer(23500)my_new_car.read_odometer()my_new_car.increment_odometer(100)my_new_car.read_odometer()####2013 Subaru OutbackThis car has 23500 miles on it.This car has 23600 miles on it.
新增的方法increment_odometer()接受一个单位为英里的数字,并将其加入到self.odometer_reading中。
继承
编写类时,并非总是要从空白开始。如果我们要编写的类时另一个现成类的特殊版本,可以考虑使用继承。一个类继承另一个类时,它将自动获得另一个类的所有属性和方法;原有的类称为父类,而新的类称为子类。子类继承其父类的所有属性和方法,同时还可以定义自己属性和方法。
3.1.1 子类的方法_init_()
下面,我们在前面创建的Car类的基础上创建新类ElectricCar,这样我们只需要为电动汽车特有的属性和行为编写代码。
class Car():--snip--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将父类和子类关联起来。这行代码让python调用ElectricCa的父类的方法_init_()。
3.1.2 给子类定义属性和方法
下面我们来添加一个电动车特有属性(电瓶),以及一个描述该属性的方法。我们将存储电瓶容量,并且编写一个打印电瓶描述的方法:
class Car():--snip--class ElectricCar(Car):def __init__(self,make,model,year):super().__init__(make,model,year)self.battery_size=70def 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.describe_battery()####2016 Tesla Model SThis car has a 70-kWh battery.
3.1.3 重写父类的方法
对于父类的方法,只要它有不符合子类模拟的实物的行为,都可以对其进行重写。为此,可以在子类中定义一个这样的方法,即它要与重写的父类方法同名。这样,python将只会关注我们在子类中定义的相应方法。
3.1.4 将实例用作属性
使用代码模拟实物时,我们可能会发现给类添加的细节越来越多:属性和方法清单以及文件都越来越长。在这种情况下,可能需要将类的一部分作为一个独立的类提取出来。我们可以将大类拆分成多个协同工作的小类。
例如,不断给ElectricCar类添加细节时,我们可能会发现其中包含很多专门针对汽车电脑电瓶的属性和方法。在这种情况下,我们可将这些属性和方法提取出来,放到另一个名为Battery的类中,并将一个Battery实例用作ElectricCar类的一个属性:
class Car():--snip--class Battery():def __init__(self,battery_size=70):self.battery_size=battery_sizedef describe_battery(self):print(\"This car has a \"+str(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\',2016)print(my_tesla.get_descriptive_name())my_tesla.battery.describe_battery()####2016 Tesla Model SThis car has a 70-kWh battery.
上面的代码看似做了很多额外的工作,但好处是现在我们多详细描述电瓶都可以,切不会导致ElectricCa类混乱不堪。下面我们继续给Battery类添加一个方法,它根据电瓶容量报告汽车的续航里程:
class Car():--snip--class Battery():--snip--def get_range(self):if self.battery_size==70:range=240elif self.battery_size==85:range=270message =\"This car can go approximately \"+str(range)message+=\"miles on a full charge.\"print(message)class ElectricCar(Car):--snip--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 SThis car has a 70-kWh battery.This car can go approximately 240miles on a full charge.
导入类
python允许我们将类存储在模块中,然后在主程序中导入所需的模块。
4.1.1 导入单个类
我们可以创建一个只包含Car类的模块,我们可以将这个模块命名为car.py。然后我们可以新创建其他文件,并在其中导入我们创建好的Car模块。
例如,我们创建新文件new_car:
from car import Carmy_new_car=Car(\'auid\',\'a4\',2016)print(my_new_car.get_descriptive_name())my_new_car.odometer_reading =23my_new_car.read_odometer()
第一句处的import语句让python打开模块car,并导入其中的Car类,这样我们就可以使用Car类了。
4.1.2 在一个模块中存储多个类
4.1.3 从一个模块中导入多个类
from car import Car,ElectriCar
4.1.4 导入整个模块
import car
4.1.5 导入模块中所有类
from module_name import *