文章目录
面向对象基础
面向对象(Object Oriented)是软件开发方法,一种编程范式。面向对象的概念和应用已超越了程序设计和软件开发,扩展到如数据库系统、交互式界面、应用结构、应用平台、分布式系统、网络管理结构、CAD技术、人工智能等领域。面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。
面向对象是相对于面向过程来讲的,面向对象方法,把相关的数据和方法组织为一个整体来看待,从更高的层次来进行系统建模,更贴近事物的自然运行模式。
对象的含义是指具体的某一个事物,即在现实生活中能够看得见摸得着的事物。在面向对象程序设计中,对象所指的是计算机系统中的某一个成分。在面向对象程序设计中,对象包含两个含义,其中一个是数据,另外一个是动作。对象则是数据和动作的结合体。对象不仅能够进行操作,同时还能够及时记录下操作结果。
方法是指对象能够进行的操作,方法同时还有另外一个名称,叫做函数。方法是类中的定义函数,其具体的作用就是对对象进行描述操作。
类及类的定义
类是一系列事务的统称,同类事务必定具有相同的特征。
举例:猫
状态:品种、年龄、重量。。。
行为:爬树、捉老鼠、卖萌。。。
特征:变量(成员变量)
行为:方法(成员方法)
成员变量和成员方法统称为类的成员。
类名的命名规范:大驼峰命名规则
类的定义 格式一
class 类名:
pass
class Cat:
pass
pass
是空语句,是为了保持程序结构的完整性。
pass
不做任何事情,一般用做占位语句。
类的定义 格式二
class 类名:
成员
对象的创建
创建格式
变量名 = 类名()
注意:创建对象不限制数量。
class Cat:
pass
cat1 = Cat()
cat2 = Cat()
cat3 = Cat()
成员变量
成员变量用于描述对象的固有状态。
定义格式一(常用)
class 类名:
def __init__(self):
self.变量名1 = 值1
self.变量名2 = 值2
self.变量名3 = None
self.变量名4 = None
调用格式
- 取值:
对象名.变量名
- 赋值:
对象名.变量名 = 值
class Cat:
def __init__(self):
# 成员变量(默认值)
self.type = "波斯猫"
# 成员变量(无默认值)
self.name = None
cat = Cat()
print(cat.type) # 波斯猫
print(cat.name) # None
print(type(cat.type)) # <class 'str'>
print(type(cat.name)) # <class 'NoneType'>
print(cat1.type) # 波斯猫
print(cat1.name) # None
cat1.name = "大帅"
print(cat1.name) # 大帅
print(cat2.type) # 波斯猫
print(cat2.name) # None
cat2.name = "小帅"
print(cat2.name) # 小帅
定义格式二(不常用)
# 此变量名不存在类的成员变量中
对象名.变量名 = 值
调用格式同格式一一致
class Cat:
def __init__(self):
# 成员变量(默认值)
self.type = "波斯猫"
# 成员变量(无默认值)
self.name = None
cat = Cat()
cat.cloth = "红色衣服"
print(cat.cloth) # 红色衣服
注意:
- 如果变量名不存在视为 定义变量
- 如果变量名存在视为 调用变量
class Cat:
def __init__(self):
# 成员变量(默认值)
self.type = "波斯猫"
# 成员变量(无默认值)
self.name = None
cat = Cat()
cat.cloth = "红色衣服" # 定义变量
print(cat.cloth) # 红色衣服
cat.cloth = "蓝色衣服" # 调用变量
print(cat.cloth) # 蓝色衣服
cat1 = Cat()
# print(cat.cloth) # 未定义就调用,将报错:AttributeError: 'Cat' object has no attribute 'cloth'
区别
- 在类定义中声明的变量为公有变量/共有属性,每个对象均存在此变量对应的属性
- 在创建对象后声明的变量为独有变量/独有属性,仅当前对象存在此变量对应的属性
成员方法
成员方法用于描述对象的固有行为。
定义格式一
class 类名:
def 方法名(self):
方法体
调用:对象名.方法名()
注意:self
仅在声明时站位,无需传递具体参数
class Cat:
def __init__(self):
self.type = "波斯猫"
self.name = None
def eat(self):
print("猫吃鱼")
def climb(self):
print("猫会爬树")
cat = Cat()
cat.eat() # 猫吃鱼
cat.climb() # 猫会爬树
定义格式二
class 类名:
def 方法名(self, 形参1, 形参2......):
方法体
调用:对象名.方法名(实参1, 实参2......)
class Cat:
def __init__(self):
self.type = "波斯猫"
self.name = None
def climb(self, meter):
print("猫会爬树, 爬了%d米" % meter)
cat = Cat()
cat.climb(5) # 猫会爬树, 爬了5米
__init__
方法
__init__
方法在创建对象时被运行,无需手动调用即可执行。
对于程序中声明、定义的方法在特定时机自动执行的方法,称为魔术方法。
__str__
方法
__str__
方法在使用 print
函数打印输出到屏幕时被运行,无需手工调用即可执行。
该方法也属于魔术方法。
定义格式:
def __str__(self):
return 打印对象时显示的信息
演示:
class Cat:
def __init__(self):
self.type = "波斯猫"
self.name = None
cat = Cat()
print(cat) # <__main__.Cat object at 0x000000000283B1D0>
0x000000000283B1D0
:内存地址值
在类中增加 __str__
方法:
class Cat:
def __init__(self):
self.type = "波斯猫"
self.name = None
def __str__(self):
return "打印了一只猫~~"
cat = Cat()
print(cat) # 打印了一只猫~~
成员方法调成员
成员方法调成员变量
调用共有成员变量
直接访问,通过 self
进行
class Cat:
def __init__(self):
self.type = "波斯猫"
self.name = None
def introduce(self):
print("我是一只%s,我叫%s" % (self.type, self.name))
cat = Cat()
cat.introduce() # 我是一只波斯猫,我叫None
cat.name = "张三"
cat.introduce() # 我是一只波斯猫,我叫张三
self
:仅出现在成员方法中,指代执行该方法(变量)的对象。
调用独有成员变量
访问要慎重,如果对象不存在该独有变量,程序将报错
class Cat:
def __init__(self):
self.type = "波斯猫"
self.name = None
def introduce(self):
print("我是一只%s,我叫%s,我穿的是%s"% (self.type, self.name, self.cloth))
cat = Cat()
cat.name = "张三"
cat.cloth = "红色衣服"
cat.introduce() # 我是一只波斯猫,我叫张三,我穿的是红色衣服
cat1 = Cat()
cat1.name = "李四"
cat1.introduce() # AttributeError: 'Cat' object has no attribute 'cloth'
成员方法调成员方法
class Cat:
def catch(self):
"""捉老鼠"""
self.jump()
self.grasp()
self.bite()
def jump(self):
print("跳起")
def grasp(self):
print("抓住")
def bite(self):
print("咬住")
cat = Cat()
cat.catch()
# 跳起
# 抓住
# 咬住
手机案例
要求
- 手机电量默认是 100
- 打游戏每次消耗电量 10
- 听歌每次消耗电量 5
- 打电话每次消耗电量 4
- 接电话每次消耗电量 3
- 充电可以为手机补充电量
分析
- 定义类
Phone
- 定义变量用于描述电量值
- 定义 4 个方法用于描述耗电操作
- 定义 1 个方法用于描述充电操作
- 运行程序,执行上述操作,观察结果
class Phone:
def __init__(self):
self.power = 100
def play_game(self):
self.power -= 10
print("打游戏")
def listen_music(self):
self.power -= 5
print("听音乐")
def call(self):
self.power -= 4
print("打电话")
def answer(self):
self.power -= 3
print("接电话")
def charge(self, num):
self.power += num
print("充了%d的电" % num)
def recharge(self):
self.power = 100
print("充满电了~~")
def __str__(self):
return "当前电量为:%d" % self.power
phone = Phone()
print(phone)
phone.play_game()
print(phone)
phone.listen_music()
print(phone)
phone.call()
print(phone)
phone.answer()
print(phone)
phone.charge(20)
print(phone)
phone.recharge()
print(phone)
打印结果:
当前电量为:100
打游戏
当前电量为:90
听音乐
当前电量为:85
打电话
当前电量为:81
接电话
当前电量为:78
充了20的电
当前电量为:98
充满电了~~
当前电量为:100
封装
封装操作可以对受访问保护的成员进行功能开放的控制,达到保护数据不被非法访问的目的。
私有
对成员私有化可以有效的保护从类的外部对类内部成员进行访问。
私有属性定义格式
self.__属性名 = 值
私有方法定义格式
方法也可以私有,也可以封装,通常不对方法做封装。
def __方法名(self):
方法体
封装标准定义格式
-
对受保护的变量进行私有设置
self.__变量名 = 值
-
提供对外访问器
访问器(get方法):
# 访问器(get方法) def get_变量名(self): return __变量名 # 修改器(set方法) def set__变量名(self, 形参): self.__变量名 = 形参
封装前
class Card:
def __init__(self):
self.card_id = None
self.password = None
c = Card()
c.card_id = "123123"
c.password = "456456"
print(c.card_id)
print(c.password)
封装后
class Card:
def __init__(self):
self.card_id = None
self.__pwd = None
def get_pwd(self):
return self.__pwd
def set_pwd(self, pwd):
self.__pwd = pwd
c = Card()
c.card_id = "123123"
c.set_pwd("789789")
print(c.card_id)
print(c.get_pwd())
__init__
传参
创建对象并进行赋值
def __init__(self, 形参列表):
self.__属性名1 = 形参1
self.__属性名2 = 形参2
......
非 __init__
传参
class Cat:
def __init__(self):
self.__type1 = None
self.__name = None
def set_type1(self, type1):
self.__type1 = type1
def get_type1(self):
return self.__type1
def set_name(self, name):
self.__name = name
def get_name(self):
return self.__name
cat = Cat()
cat.set_type1("英格兰短毛猫")
cat.set_name("小短")
print(cat.get_type1()) # 英格兰短毛猫
print(cat.get_name()) # 小短
__init__
传参
class Cat:
def __init__(self, type1, name):
self.__type1 = type1
self.__name = name
def set_type1(self, type):
self.__type1 = type
def get_type1(self):
return self.__type1
def set_name(self, name):
self.__name = name
def get_name(self):
return self.__name
cat = Cat("英格兰短毛猫", "小短")
print(cat.get_type()) # 英格兰短毛猫
print(cat.get_name()) # 小短
面向对象高级
类变量
类中的成员变量描述对象的属性值根据对象不同,会产生区别,称此类变量为实例变量。
类中的成员变量描述对象的属性值根据对象不同,不会产生区别,称此类变量为类变量。
类变量是归属类的,实例变量是归属对象的。
定义格式
class 类名:
变量名 = 值
调用格式
# 赋值
类型.变量名 = 值
# 取值
类名.变量名 # 推荐
对象名.变量名 # 不推荐
注意事项
- 类变量推荐使用类名访问,可以使用对象名访问
- 类变量只能通过类名修改,使用对象修改类变量是创建了新的对象变量(独有变量)
- 类变量可以私有化
演示
class Cat:
subject = "猫科"
def __init__(self, type1, name):
self.__type1 = type1
self.__name = name
def set_type1(self, type1):
self.__type1 = type1
def get_type1(self):
return self.__type1
def set_name(self, name):
self.__name = name
def get_name(self):
return self.__name
print(Cat.subject) # 猫科
cat1 = Cat("英格兰短毛猫", "小短")
print(cat1.subject) # 猫科
cat2 = Cat("加菲猫", "小加")
print(cat2.subject) # 猫科
cat1.subject = "猫"
print(cat1.subject) # 猫(cat1增加了一个独有变量)
print(Cat.subject) # 猫科
print(cat2.subject) # 猫科
Cat.subject = "猫星人"
print(Cat.subject) # 猫星人
print(cat1.subject) # 猫(独有变量)
print(cat2.subject) # 猫星人
类方法
定义格式
@classmethod
def 方法名(cls, 形参列表):
方法体
调用格式
类名.方法名(实参列表) # 推荐
对象名.方法名(实参列表) # 不推荐
演示
class Chinese:
country = "中国"
def __init__(self, id_num, name):
self.id_num = id_num
self.name = name
@classmethod
def show_country(cls):
print("我的国籍是%s" % cls.country)
Chinese.show_country() # 我的国籍是中国
c = Chinese("123", "张三")
c.show_country() # 我的国籍是中国
注意事项
- 类方法中不允许使用实例变量和实例方法
- 实例方法中允许使用类变量和类方法
class Chinese:
country = "中国"
def __init__(self, id_num, name):
self.id_num = id_num
self.name = name
@classmethod
def show_country(cls):
print("我的国籍是%s" % cls.country)
@classmethod
def call_country(cls):
"""类方法调用实例的成员"""
print("我是中国人!!!")
print(self.name) # 执行会报错
self.show_name() # 执行会报错
def show(self):
"""实例方法调用类成员"""
print(self.name)
print(Chinese.country)
Chinese.show_country()
def show_name(self):
"""实例方法调用类成员"""
print(self.name)
c = Chinese("123", "张三")
c.show()
# 中国
# 我的国籍是中国
Chinese.call_country() # 报错
类方法调用实例的成员,被调用执行才会报错(不执行不报错)。
self
、cls
:自动补充,下方示例的三个实例方法中self
、a
、cls
含义及作用一样# self仅是个自动补充的变量,代表对象本身 def show_name(self): print(self.name) # a,同self一样,仅是个自动补充的形参变量,代表对象本身 def show_name(a): print(a.name) # cls,此处cls,同a和self一样,仅是个自动补充的形参变量,代表对象本身 def show_name(cls): print(cls.name)
只有带有
@classmethod
的方法,才是类方法,类方法的第一个参数cls
也是个自动补充的形参变量。
静态方法
定义格式
class 类名:
@staticmethod
def 方法名(形参列表):
方法体
调用格式
类名.方法名(实参列表)
对象名.方法名(实参列表)
静态方法与类无关,可以将其转换成函数使用。
演示
class Chinese:
country = "中国"
def __init__(self):
pass
@staticmethod
def show():
print("张三李四王五赵六")
def show():
"""直接定义成函数,无需类和对象调用"""
print("张三李四王五赵六")
Chinese.show() # 张三李四王五赵六
c = Chinese()
c.show() # 张三李四王五赵六
# 直接调用
show() # 张三李四王五赵六
面向对象名称总结
变量称呼
称呼 | 使用量排序 |
---|---|
全局变量 | 5 |
局部变量 | 2 |
公有变量 | 1 |
独有变量 | 5 |
私有变量 | 3 |
类变量 | 4 |
其他称呼 | 含义 |
---|---|
成员变量 | 公有变量 |
对象变量(对象的XXX变量) | 对象的变量 |
对象属性(对象的XXX属性) | 对象的属性,同对象的变量 |
演示
class User:
country = "类变量"
__title = "类变量,私有变量"
def __init__(self):
self.name = "公有变量"
self.__age = "公有变量,私有变量"
info = "局部变量"
def test(self):
self.address = "公有变量" # 共有变量建议全部定义在 __init__ 构造方法中
email = "局部变量"
u = User()
u.gender = "独有变量"
city = "全局变量"
info = "全局变量"
def test():
info = "局部变量"
global city # 全局变量
city = "全局变量"
方法称呼
称呼 | 使用量排序 |
---|---|
方法(一般指实例方法) | 1 |
类方法 | 2 |
静态方法 | 4 |
函数 | 3 |
其他称呼 | 含义 |
---|---|
成员方法 | 实例方法 |
构造方法 | __init__ 方法 |
class User:
def __init__(self, name, age):
self.name = name
self.age = age
print("构造方法")
def instance_method(self, info):
message = "你好"
name = self.name
print("实例方法,成员方法")
@classmethod
def class_method(cls):
message = "你好"
print("类方法")
@staticmethod
def static_method():
message = "你好"
print("静态方法")
对象称呼
称呼 | 含义 |
---|---|
对象 | 同实例 |
实例 | instance ,同对象含义一样 |
class User:
pass
u = User() # u:对象,也称为实例
继承
继承是一种类间关系,描述一个类从另一个类获取成员信息的类间关系。
继承必定发生在两个类之间,参与继承关系的双方称为父类和子类。
父类提供成员信息,子类获取成员信息。
定义格式:
class 子类(父类):
pass
继承父类的成员:
- 成员变量
- 成员方法
注意事项:
- 子类可以添加父类没有的成员
- 父类私有成员不可被继承
class Animal:
type = "动物"
def __init__(self):
self.name = None
self.__age = None
def show(self):
print("我的名字是%s" % self.name)
class Cat(Animal):
def climb(self):
"""子类可以添加父类没有的成员"""
print("我的名字是%s,会爬树" % self.name)
c = Cat()
c.name = "张三"
print(c.name) # 张三
c.show() # 我的名字是张三
print(Cat.type) # 动物 (不建议子类调用父类的类变量)
print(Animal.type) # 动物
c.climb() # 我的名字是张三,会爬树
# print(c.__age) # 父类私有成员不可被继承
object
类是所有类的父类
class 类名(object):
pass
使用 类名.__mro__
可以查看继承关系链
class Animal:
pass
class Cat(Animal):
pass
class PersianCat(Cat):
pass
print(Animal.__mro__) # (<class '__main__.Animal'>, <class 'object'>)
print(Cat.__mro__) # (<class '__main__.Cat'>, <class '__main__.Animal'>, <class 'object'>)
print(PersianCat.__mro__)
# (<class '__main__.PersianCat'>, <class '__main__.Cat'>, <class '__main__.Animal'>, <class 'object'>)
重写
在子类中可以定义与父类相同名称的方法,此时子类的方法对父类的方法构成了重写。
如果子类重写了父类的方法,使用子类对象调用被重写的方法时时,执行子类中重写后的方法。
class Animal:
def eat(self):
print("动物吃东西")
class Cat(Animal):
def eat(self):
print("猫吃鱼")
c = Cat()
c.eat() # 猫吃鱼
print(c) # <__main__.Cat object at 0x0000021EB67D91D0>
class Cat:
def eat(self):
print("猫吃鱼")
def __str__(self):
return "喵咪"
print(c) # 喵咪
在子类中调用父类中被重写的实例方法
# 调用格式一:
父类名.方法名(对象)
# 调用格式二:
super(本类名, 对象).方法名()
# 调用格式三(推荐):
super().方法名()
class Animal:
def __init__(self):
print("动物被创建")
def eat(self):
print("动物吃东西")
class Cat(Animal):
def __init__(self):
super().__init__()
print("猫被创建")
def eat(self):
print("猫吃鱼")
# 格式一
Animal.eat(self)
# 格式二
super(Cat, self).eat()
# 格式三
super().eat()
def __str__(self):
s = super().__str__()
print("super().__str__(): %s" % s)
return "喵咪"
c = Cat()
print("---------------------")
c.eat()
print("---------------------")
print(c)
动物被创建
猫被创建
---------------------
猫吃鱼
动物吃东西
动物吃东西
动物吃东西
---------------------
super().__str__(): <__main__.Cat object at 0x00000186A2E49860>
喵咪
多继承
定义格式
class 类名(父类名1, 父类名2, ......):
pass
演示
简单多继承
class Father:
def sing(self):
print("爸爸会唱歌")
class Mother:
def dance(self):
print("妈妈会跳舞")
class Children(Father, Mother):
pass
c = Children()
c.sing() # 爸爸会唱歌
c.dance() # 妈妈会跳舞
多继承重名方法(默认执行靠前的父类中的方法)
class Father:
def sing(self):
print("会唱歌")
def dance(self):
print("跳舞很丑")
class Mother:
def dance(self):
print("会跳舞")
def sing(self):
print("唱歌难听")
class Children(Father, Mother):
pass
c = Children()
c.sing() # 会唱歌
c.dance() # 跳舞很丑
多继承重名方法,指定父类中的方法
class Father:
def sing(self):
print("会唱歌")
def dance(self):
print("跳舞很丑")
class Mother:
def dance(self):
print("会跳舞")
def sing(self):
print("唱歌难听")
class Children(Father, Mother):
def sing(self):
print("孩子不会唱歌")
Father.sing(self)
Mother.sing(self)
Father.dance(self)
Mother.dance(self)
c = Children()
c.sing()
# 孩子不会唱歌
# 会唱歌
# 唱歌难听
# 跳舞很丑
# 会跳舞
多态
一个对象具有多种形态,在不同的使用环境中以不同的形态展示其功能,称该对象具有多态特征。
多态发生在继承关系的基础之上。
class Teacher:
def teach(self):
print("教授知识")
class Driver:
def drive(self):
print("开车")
class Man(Teacher, Driver):
def teach(self):
print("教授Java知识")
def drive(self):
print("开跑跑卡丁车")
class Demo:
def play(self, driver):
driver.drive()
def study(self, teacher):
teacher.teach()
demo = Demo()
# 方案一:直接创建对象
d = Driver()
demo.play(d) # 开车
t = Teacher()
demo.study(t) # 教授知识
# 方案二:创建一个具有指定特征的对象
man = Man()
demo.play(man) # 开跑跑卡丁车
demo.study(man) # 教授Java知识
鸭子类型
对象在语法层面满足调用关系,实际不具有对应的对象形态,称该对象此时具备鸭子类型。
鸭子类型是一种特殊的多态表现形式。
class Teacher:
def teach(self):
print("教授知识")
class Man(Teacher):
def teach(self):
print("教授Java知识")
class GamePlayer:
def teach(self):
print("教玩游戏")
class Demo:
def dothing(self, teacher):
teacher.teach()
demo = Demo()
t = Teacher()
demo.dothing(t) # 教授知识
m = Man()
demo.dothing(m) # 教授Java知识
# g:鸭子类型
g = GamePlayer()
demo.dothing(g) # 教玩游戏