目录
根据类来创建对象称为实例化
一、创建和使用类
使用类几乎可以模拟任何东西。编写一个表示小狗的简单类Dog,它表示的不是特定的小狗,而是任何小狗。大多数小狗具备两项信息(名字和年龄)和两种行为(蹲下和打滚),
Dog类将包含。
1.创建Dog类
类:首字母大写,类定义中没有圆括号,因为要从空白创建这个类。方法:类中的函数。
class Dog:
"""一次模拟小狗的简单尝试"""
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__( )
方法__init__( )是个特殊的方法,开头和末尾各有两个下划线,避免python默认方法和普通方法发生名称冲突,否则用类来创建实例时,不会自动调用这个方法。方法__init__( )中包含三个参数,self、name和age,形参self必不可少,且必须位于最前面。
Python调用这个方法来创建Dog实例时,每个与实例相关联的方法调用都自动传递实参self。创建Dog实例时,Python将调用Dog类的方法__init__(),只需通过实参向Dog()传递名字和年龄,self会自动传递。
self.name = name、self.age = age,定义的两个变量都有前缀self,以self为前缀的变量可供类中所有的方法使用,可通过类的任何实例来访问。通过实例来访问的变量称为属性。
方法sit( )和方法roll_over( )执行时不需要额外信息,故只有一个形参self
2.根据类来创建实例
可将类作为创建实例的说明。通常用首字母大写的名称来表示类(Dog),小写的字母是根据类创建的实例(my_dog)。首先要在实例和类之间建立关联。
class Dog:
"""一次模拟小狗的简单尝试"""
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!")
my_dog = Dog('Willie',6) #首先在实例与类之间建立关联 使用实参调用类中的方法_init_,方法_init_创建一个小狗的实例,实例赋给变量my_dog
print(f"My dog's name is {my_dog.name}.")
print(f"My dog's name is {my_dog.age}.")
My dog's name is Willie.
My dog's name is 6.
a.访问属性 在实例中用实例+.属性(my_dog.name),在 类中用self+.属性(self.name)
访问实例的属性,可使用句点表示法。python先找到实例,再查找相关联的属性name 实例+.属性;在Dog类中引用这个属性时,使用的是self.name self+.属性
my_dog.name
b.调用方法:实例名称+.方法
根据类创建实例后,可用句点表示法来调用类中定义的任何方法。
class Dog:
def __init__(self,name,age):
self.name = name
self.age = age
def sit(self):
print(f"{self.name} is now sitting.")
def roll_up(self):
print(f"{self.name} rolled over!")
my_dog = Dog('Willie',6)
my_dog.sit() #python在类Dog中查找方法sit()并运行其代码
my_dog.roll_up()
Willie is now sitting.
Willie rolled over!
c.创建多个实例
可按需求根据类创建任意数量的实例,条件是每个实例粗出在不同的变量中。
class Dog:
def __init__(self,name,age):
self.name = name
self.age = age
def sit(self):
print(f"{self.name} is now sitting.")
def rolled_up(self):
print(f"{self.name} rolled over!")
my_dog = Dog('Willie',6)
your_dog = Dog('Lucy',3)
print(f"My dog's name is {my_dog.name}.")
print(f"My dog is {my_dog.age} years old.")
my_dog.sit()
print(f"\nYour dog's name is {your_dog.name}.")
print(f"Your dog is {your_dog.age} years old.")
your_dog.sit()
My dog's name is Willie.
My dog is 6 years old.
Willie is now sitting.
Your dog's name is Lucy.
Your dog is 3 years old.
Lucy is now sitting.
二、使用类和实例
类编写好后,主要是根据类创建实例。常做的就是修改实例的属性,可直接修改实例的属性,也可编写方法以特定的方式修改。在函数体中如果没有print,就会出现return,除去__init__特殊方法。
class Car:
def __init__(self,make,model,year):
self.make = make
self.model = model
self.year = year #self.make self.model self.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) #实例中的顺序要和方法中的__init__保持一致
print(my_new_car.get_descriptive_name())
2019 Audi A4
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 = 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.")
my_new_car = Car('audi','a4',2019)
print(my_new_car.get_descriptive_name())
my_new_car.read_odometer()
2019 Audi A4
This car has 0 miles on it.
2.修改属性的值
可以直接通过实例修改,可通过方法进行设置,可通过方法进行递增(增加特定的值)。
a.直接修改属性的值:直接访问属性修改 实例+.属性=另一个值
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.")
my_new_car = Car('audi','a4',2019)
print(my_new_car.get_descriptive_name())
my_new_car.odometer_reading = 36 #让python在实例my_new_car中找到属性odometer_reading,修改属性值
my_new_car.read_odometer()
2019 Audi A4
This car has 36 miles on it.
b.通过方法修改:用方法来更新属性,将值传递给方法,在内部进行更新。
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,若还有其他运算,可添加其他形参
self.odometer_reading = mileage #将mileage的值赋给self.odometer_reading,不一定要返回return
my_new_car = Car('audi','a4',2019)
print(my_new_car.get_descriptive_name())
my_new_car.update_odometer(36) #调用update_odometer(),并提供实参36
my_new_car.read_odometer()
对方法update_odometer()进行拓展,禁止将里程表读书往回调,控制用户修改属性值,但仍可以通过直接修改属性来修改。
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 #对类中方法__init__()方法中变量的使用都应用等号左侧(包含self)
else:
print("You can'nt roll back an odometer!")
my_new_car = Car('audi','a4',2019)
print(my_new_car.get_descriptive_name())
my_new_car.update_odometer(36)
my_new_car.read_odometer()
c.通过方法对属性的值进行递增
将属性值递增特定的量,不是将其设为全新的值。
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 #对类中方法__init__()方法中变量的使用都应用等号左侧(包含self)
else:
print("You can'nt roll back an odometer!")
def increment_odometer(self,miles): #在类中添加方法,对值进行递增
self.odometer_reading += miles #对self.odometer_reading增加miles的值
my_new_car = Car('audi','a4',2019)
print(my_new_car.get_descriptive_name())
my_new_car.update_odometer(23_500)
my_new_car.read_odometer()
my_new_car.increment_odometer(300)
my_new_car.read_odometer()
2019 Audi A4
This car has 23500 miles on it.
This car has 23800 miles on it.
三、继承
若编写的类是现成类的一个特殊版本,可使用继承。B类继承A类时,将获得A类所有的属性和方法,还可以定义自己的属性高和方法。A类称为父类,B类称为子类。
1.子类的方法__init__()
创建子类—圆括号内得包括父类名字;定义特殊方法def __init__(属性);调用父类方法super()__init__(实际属性);实例;打印输出。
super( )是一个特殊函数,能够调用父类的方法。父类也称为超类,名称由此而来。
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): #方法__init__()接受创建Car所需的实例
super().__init__(make,model,year) #调用Car类的方法,ElectricCar实例包含这个方法中定义的所有属性
my_tesla = ElectricCar('tesla','models','2019')
print(my_tesla.get_descriptive_name())
2019 Tesla Models
2.给子类定义属性和方法
在子类中创建新属性,ElectricCar类创建的所有实例都将包含该属性,但所有Car实例将不会包括。如果一个属性和方法是任何汽车都有的,应将其加入到Car类而非ElectricCar类中。
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.")
my_tesla = ElectricCar('tesla','models','2019')
print(my_tesla.get_descriptive_name())
my_tesla.describe_battery()
2019 Tesla Models
This car has a 75-kWh battery.
3.重写父类的方法
可在子类中定义一个与父类方法同名的方法,python将不会考虑父类的方法,只关注在子类中定义的相应方法。可取其精华,去其糟粕。假设Car类中有一个名为fill_gas_tank( )的方法,对全电动汽车来说毫无意义,可在子类中重写。
class ElectricCar(Car):
--snip--
def fill_gas_tank(self):
print("This car doesn't need a gas tank!")
4.将实例用作属性
可以将大型的类拆分成多个协同工作的小类。不断给ElectricCar类添加细节,发现很多正对汽车电瓶的属性和方法,可将其提取出来,放到一个名为Battery的类中,并将一个Battery实例作为ElectricCar类的属性。
self.battery = Battery() #添加了一个名为self.battery的属性,让python创建了一个新的Battery实例,并将该实例赋给属性self.battery
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 Battery: #定义了一个名为Battery的类,没有继承任何类
def __init__(self,battery_size = 75): #方法__init__()除了self外,还提供了可选形参battery_size
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() #将实例Battery作属性self.battery
my_tesla = ElectricCar('tesla','models',2019)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery() #在实例myn_tesla中查找属性battery,并对存储在该属性中的Battery实例调用方法describe_battery()
2019 Tesla Models
This car has a 75-kWh battery.
给Battery类再添加一个方法
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 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.")
def get_range(self):
if self.battery_size == 75:
range = 260
elif self.battery_size == 100:
range = 315
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_tesla = ElectricCar('tesla','models',2019)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
my_tesla.battery.get_range() #通过汽车的属性来调用方法
2019 Tesla Models
This car has a 75-kWh battery.
This car can go about 260 miles on a full charge.
5.模拟实物
从较高的逻辑层面(而不是语法层面)考虑。考虑的不是Python,而是如何使用代码来表示实物。达到这种境界后,你会经常发现,对现实世界的建模方法没有对错之分。有些方法的效率更高,但要找出效率最高的表示法,需要经过一定的实践。
四、导入类
为了让文件尽可能的简洁,可将类存储在模块中,然后在主程序中导入所需的模块
模块:是后缀名为.py的文件
1.导入单个类
将Car类存储在一个名为car.py的文件中,该模块将覆盖前面使用的文件car.py。使用该模块的程序都必须使用更具体的文件名,如my_car.py。
只包含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'nt roll back an odometer!")
def increment_odometer(self,miles):
"""将里程表读数增加指定值"""
self.odometer_reading += miles
创建另一个文件my_car.py
import语句让python打开模块car并导入其中的Car类,就如同在这个文件中定义的一样。
from car import Car
my_new_car = Car('audio','a4',2019)
print(my_new_car.get_descriptive_name())
my_new_car.odometer_reading = 23
my_new_car.read_odometer()
2019 Audio A4
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):
"""设定汽车的里程值,拒绝将里程表往回调"""
if mileage >= self.odometer_reading:
self.odometer_reading = mileage
else:
print("You can'nt roll back an odometer!")
def increment_odometer(self,miles):
"""将里程表读数增加指定值"""
self.odometer_reading += miles
class Battery:
"""一次模拟电动汽车电瓶的简单尝试"""
def __init__(self,battery_size = 75):
"""初始化电瓶的属性"""
self.battery_size = battery_size
def descriptive_battery(self):
"""打印一条描述电瓶容量的信息"""
print(f"This car has a {self.battery_size}-KWh battery.")
def get_range(self):
"""打印一条描述电瓶续航的消息"""
if self.battery_size == 75:
range = 260
elif self.battery_size == 100:
range = 315
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的文件,导入ElectricCar类
from car import ElectricCar
my_tesla = ElectricCar('tesla','models',2019)
print(my_tesla.get_descriptive_name())
my_tesla.battery.descriptive_battery()
my_tesla.battery.get_range()
2019 Tesla Models
This car has a 75-KWh battery.
This car can go about 260 miles on a full charge.
3.从一个模块中导入多个类
从一个模块中导入多个类时,用逗号分隔了各个类。将Car类和ElectricCar类都导入
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())
2019 Volkswagen Beetle
2019 Tesla Roadster
4.导入整个模块
可以先导入整个模块,再用句点表示法访问需要的类。因为创建实例的代码都包含模块名,所以不会与当前文件使用的任何名称发生冲突。 从大到小
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())
2019 Volkswagen Beetle
2019 Tesla Roadster
5.导入模块中所有的类
可使用语法 from module_nameimport *
不推荐:a.只看文件开头的import语句,就能清楚的知道程序使用 哪些类 b.可能引发名称的迷惑,如果不小心导入了一个与程序文件中其他东西同名的类,将引发难以诊断的错误.
若需从一个模块中导入很多类时,可使用4.导入整个模块的方式,即module_name.ClassName语法,可清楚知道哪些地方使用了导入的模块,也避免导入模块中的每个类可能引发的名称冲突。
6.在一个模块中导入另一个模块
有时需要将类分散到多个模块中,以免模块太大或一个模块中存储不相关的类
ElectricCar类需要访问其父类Car,因此直接将Car类导入模块,还需更新模块car,使其只包括Car类。一个模块包含Car类(car.py),一个模块包含Battery类和ElectricCar类(electric_car.py)
from car import Car
class Battery:
"""一次模拟电动汽车电瓶的简单尝试"""
def __init__(self,battery_size = 75):
"""初始化电瓶的属性"""
self.battery_size = battery_size
def descriptive_battery(self):
"""打印一条描述电瓶容量的信息"""
print(f"This car has a {self.battery_size}-KWh battery.")
def get_range(self):
"""打印一条描述电瓶续航的消息"""
if self.battery_size == 75:
range = 260
elif self.battery_size == 100:
range = 315
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()
可分别从每个模块中导入类
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())
2019 Volkswagen Beetle
2019 Tesla Roadster
7.使用别名
导入类时,可指定别名。如程序中创建大量电动汽车实例,需反复输入ElectricCar,繁琐,可在import语句中给ElectricCar指定一个别名。
from electric_car import ElectricCar as EC
my_tesla = EC('tesla','roadster',2019)
8.自定义工作流程
一开始让代码结构尽可能简单,先尽可能在一个文件中完成所有工作,确定正常运行后,再将类移到独立的模块中
也可正在项目开始时就尝试将类存储再模块中。
五、python标准库
python标准库时一组模块,安装的python都包含。可以使用标准库中的任何函数和类,只需在程序开头包含简单的import语句
random模块中函数randint( )很有趣,将两个整数作为参数,随机返回一个位于两个数之间的参数
>>> from random import randint
>>> randint (1,6)
1
另一个函数choice( )也很有用,将列表或元组作为参数,并随机返回其中的一个元素。
>>> from random import choice
>>> players = ['charles','martina','michael','florence','eli']
>>> first_up = choice(players)
>>> first_up
'michael'
创建与安全相关的应用程序时,不要使用random,但可以创建众多有趣的项目。
六、类编码风格
与类相关的编码风格。类名应采用驼峰命名法,即类名中的每个单词的首字母大写而不使用下划线,实例名和模块名用小写格式,并在单词之间加上下划线。
对于每个类,都应紧跟在类的后面包含一个文档字符串,简要描述类的功能,每个模块也应包含一个文档字符串,描述用途。
可用空行来组织代码,但不能滥用。在类中可用一个空行来分割方法,模块中可用两个空行来分割类。
需同时导入标准库的模块和自己写的模块时,先编写导入标准库模块的import语句,再添加空行,然后编写导入自己编写模块的import语句。