类
面向对象
面向对象(Object Oriented)缩写OO,是一种设计思想。
面向对象编程(Object Oriented Programming)缩写OOP。
可以使软件设计更加灵活,更好的进行代码复用。
面向对象程序设计的特点
封装:
将对象的属性和行为封装起来成为类;是面向对象的核心思想;
类通常会对外隐藏实现细节,使用该类的用户不能看见类中的数据结构,避免外部对内部数据的影响,提高程序可维护性;
继承:
子类可通过继承复用父类的属性和行为;
多态:
子类继承父类特征同时,也具备自己的属性和行为,实现不同的效果;
类
具有相同属性和行为的一类叫做类;如人类,鸟类等;
使用class关键字定义;
语法
class ClassName:
'''类的帮助信息'''
statement|pass|... #类体
#ClassName:指定类名,采用驼峰式命名法
#类的帮助信息:创建类的对象时,输入类名和左侧的括号,将显示该信息
#statement:类体,主要有类的属性、方法构成,可使用pass空语句占位
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 rol_over(self):
'''模拟小狗听到命令时打滚'''
print(self.name.title() +'rolled over!')
''''根据类创建实例'''
my_dog = Dog('xiaobai',6)
print('My dog\'s ' + my_dog.name.title() +'.')
print('My dog is '+str(my_dog.age)+'years old.')
'''
---------------脚本执行结果--------------------
My dog's Xiaobai.
My dog is 6years old.
'''
类的实例
对象是类的实例;凭类造对象;
案例
your_dog = Dog('xiaobai',5) #生成小狗的实例
print(your_dog) #out: <__main__.Dog object at 0x000001D1F387FAC8>
#直接打印对象会告诉你这个对象的内存地址,self参数就是传递对象的地址
创建类的成员
类的成员包括类方法跟属性;
创建类方法
即类中定义的函数,也是类的行为;如如人类,有跑步,学习,睡觉等行为;
注意:实例方法第一个参数必须时self,必须包含一个self参数;
语法
#创建实例方法
def functionName(self,parameterlist):
block #方法体
#访问实例方法
instanceName.functionName(parametervalue)
案例
可参考小狗案例
#定义一个人的类
class Person:
race='人种'
gender='中性'
def study(self):
print('正在学习',self.look)
ruirui=Person()
ruirui.look='学python'
ruirui.study() #out:正在学习 学python
xiaowei=Person()
xiaowei.look='学java'
xiaowei.study() #out:正在学习 学java
'''
self表示自身对象,生成的ruirui对象会将自己传入Person类中的study()中的self,
即self是对象的地址,从而self可以调用ruirui对象的look属性
'''
创建类属性
即类中定义的变量,包括类属性跟实例属性;
类属性:类中定义的变量,可通过类名或实例名访问;
案例
#通过类名访问
class Geese:
#大雁类
neck ='长脖子'
wing ='飞的高'
leg ='大长腿'
def __init__(self): #实例化对象先执行的方法,相当于java中的构造方法
print('我是大雁,我有以下特征:')
print(Geese.neck)
print(Geese.wing)
print(Geese.leg)
Geese.neck='脖子很长很长很长' #通过类名访问属性并修改它,可以看到输出的内容不再是默认的长脖子
wldGoose = Geese() #生成大雁类的实例
'''
---------------脚本执行结果--------------------
我是大雁,我有以下特征:
脖子很长很长很长
飞的高
大长腿
'''
'''通过实例名访问'''
class Geese:
'''大雁类'''
neck ='长脖子'
wing ='飞的高'
leg ='大长腿'
def __init__(self): #实例化对象先执行的方法,相当于java中的构造方法
print('我是大雁,我有以下特征:')
print(self.neck)
print(self.wing)
print(self.leg)
wldGoose = Geese()
'''
---------------脚本执行结果--------------------
我是大雁,我有以下特征:
长脖子
飞的高
大长腿
'''
实例属性:类中方法中的变量,只能通过实例名访问;
实例属性案例
'''只能通过实例名访问'''
class Geese:
'''大雁类'''
def __init__(self): #实例化对象先执行的方法,相当于java中的构造方法
self.neck = '长脖子'
self.wing = '飞的高'
self.leg = '大长腿'
print('我是大雁,我有以下特征:')
print(self.neck)
print(self.wing)
print(self.leg)
wldGoose = Geese()
魔术方法__init__()
每创建一个类的实例后,都会自动执行此方法;
__init__()
:必须包含一个self参数,并且位置是在第一位,该参数指向实例本身的引用,即对象;
方法调用时会自动传递实际参数self,如果没有其他参数,实例化对象可不写self;
案例
class Geese:
'''大雁类'''
def __init__(self): #实例化对象先执行的方法,相当于构造方法
print('我是大雁')
wildGoose = Geese() #生成大雁类的实例,out:我是大雁
#增加其他参数
class Person:
def __init__(self,name,age): #用来放共有的属性
self.name = name
self.age = age
def eat(self):
print('{}正在吃红烧肉!'.format(self.name))
def run(self):
print('{},今年{}岁,正在跑步!'.format(self.name,self.age))
p = Person('张三',18)
p.eat() #out:张三正在吃红烧肉!
p.run() #out:张三,今年18岁,正在跑步!
访问限制
在类的属性或方法名前添加下划线可闲置访问权限;
__init__
:特殊方法,由系统定义;
_foo
:protected(保护),只允许类本身和子类访问,以及实例访问;
案例
class Swan:
'''天鹅类'''
_neck_swan='天鹅的脖子很长'
swan = Swan()
print(swan._neck_swan) #out:天鹅的脖子很长
__foo
:private(私有),只允许定义该方法的类本身访问,不能通过类的实例访问,但可以通过类的实例名._类名.__变量名或方法名方式访问;
案例
class Swan:
'''天鹅类'''
__neck_swan='天鹅的脖子很长'
swan = Swan()
print(swan._Swan__neck_swan) #out:天鹅的脖子很长
将方法转换为属性
在python中可以通过@property(装饰器)将一个方法转换为属性,转换为属性后可直接通过方法名来访问方法,不需要添加小括号;
注意:通过@property转换后的属性不能重新赋值,如果创建一个只能读取不能修改的属性,可以使用@property
案例
'''定义一个计算矩形面积的类'''
class Rect:
def __init__(self,width,height):
self.width = width
self.height = height
'''使用@property将方法转换为属性'''
@property
def area(self):
return self.width*self.height
'''创建计算矩形面积的类的实例'''
rect = Rect(800,600)
'''调用类中由方法转换成的属性'''
print('面积为:',rect.area)
#out:面积为: 480000
继承
一个类继承另一个类,它将自动获得另一个类所有属性和方法;
原有的类称为父类或基类以及超类,新类称为子类,子类除了继承父类所有属性和方法还可以定义自己的属性和方法;
注意:创建子类时,父类必须包含在当前文件中,且位于子类前面;
案例
'''定义一个水果类'''
class Fruit:
'''定义类属性'''
color = '绿色'
def harvest(self,color):
'''输出形参的color'''
print('水果是:',color,'的')
print('水果已经收获...')
'''输出类属性的color'''
print('水果原来是:',Fruit.color,'的')
'''定义派生类,需要在括号中写明父类'''
class Orange(Fruit):
color = '橙色'
def __init__(self):
print('我是橘子')
'''重写父类方法'''
def harvest(self,color):
print('橘子是:'+color+'的')
print('橘子已经收获...')
'''可以调用父类属性'''
print('橘子原来是:'+Fruit.color+'的')
orange=Orange()
orange.harvest('黄色')
'''
---------------脚本执行结果--------------------
我是橘子
橘子是:黄色的
橘子已经收获...
橘子原来是:绿色的
'''
案例
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
my_userd_car = Car('subaru','outback',2013) #假如购买了一辆subaru,型号outback,2013年出厂的车
print(my_userd_car.get_descriptive_name()) #out:2013 Subaru Outback
my_userd_car.update_odometer(23500)
my_userd_car.read_odometer() #out:This car has 23500miles on it.
my_userd_car.update_odometer(100) #out:You can't roll back an odometer!
#创建电动车类,继承汽车类
class ElectricCar(Car):
def __init__(self,make,model,year):
#初始化父类属性
super().__init__(make,model,year) #super()是一个特殊函数,可以让子类调用父类的__init__(),由此父类也称为超类
#电动车独特属性
self.battery_size =70
#打印描述电量的方法
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()) #out:2016 Tesla Model S
my_tesla.describe_battery() #out:This car has a 70-kWh battery.
重写父类方法
子类的方法名要与父类的方法同名,才可重写父类的方法;
案例
#假设父类中有fill_gas_tank()方法,但是子类电动车类没有油箱则可以如下重写
def ElectricCar(Car):
#与要重写的父类方法同名
def fill_gas_tank():
#电动车没有油箱
print('This car doesn\'t need a gas tank!')
将实例转换为属性
当类的属性方法越来越多,可以将其部分独立出来当作一个类来处理;
案例
#将电动车ElectricCar类中的属性跟方法独立出来成为一个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.')
#定义ElectricCar类继承Car类
class ElectricCar(Car):
def __init__(self,make,model,year):
#初始化父类属性
super().__init__(make,model,year)
#将Battery类实例化成为电动汽车类对象的属性
self.battery = Battery()
my_tesla=ElectricCar('tesla','model s',2016)
my_tesla.battery.describe_battery() #out:This car has a 70-kWh battery.
导入类
为了py文件尽可能的整洁,可将类单独保存成模块,在需要的时候导入即可;
导入单个类
例如:将Car()类单独保存成为car.py文件
在需要使用该类的py文件开头导入该类
#格式为 from 模块名 import 类名
from car import Car
导入多个类
类与类之间使用逗号分开;
from car import Car,ElectricCar
导入整个模块
导入整个模块,再使用句点表示要访问的类;
import car
my_beetle = car.Car('volkswagen','beetle',2016)
my_tesla = car.ElectricCar('tesla','roadster',2016)
在一个模块中导入另一个模块
有时候将类存储在多个模块中时,可能会发现一个模块中的类依赖于另一个模块中的类,这种情况下需要依次导入必要的类;
#例如:car.py模块中包含Car类,electric_car.py模块中包含ElectricCar和Battery类,其中ElectricCar继承Car类
from car import Car #先导入父类
from electric_car import ElectricCar #再导入电瓶车类
学习来自:《python从入门到项目实践》明日科技 第十一章
《Python编程:从入门到实践》第九章 (参考一下豆瓣神书,针不戳)
B站大学 P82-P96