面向对象是程序设计封装的一种思想 ! ! !
1,列表是将各种不同的数据类型的数据封装到一个容器里面 --> 数据层面的封装
2,函数是将一段代码封装到一起 --> 语句层面的封装
3,面向对象是将具有相同属性和方法的代码封装到一起 --> 程序设计层面的封装
那么 为什么要用面向对象呢?
面向对象的好处:拓展性强,比方王者荣耀新增一个英雄很方便。
解耦和,降低程序的维护成本
类是模板,具有相同特征和行为的一类事务。
比如说王者荣耀里面的 射手类 法师类 战士类 刺客类等等
对象是一个由具体产生的实例,比方说:射手类-->鲁班,法师类-->妲己
写在类里面的函数称之为方法
例如 定义一个射手类
class sheshou:
"""射手类"""
#类的属性(一般指的是变量)
gongji = 1700 #攻击力
fangyu = 300 防御力
#行为(实例方法)
def sheji(self)
print("我的攻击力是:{},防御能力是:{}".format(self.gongji,self.fanyu))
luban = Sheshou() #实例化,将类实例化出一个具体的对象,由射手类创建出一个鲁班对象
print(luban) #打印出来的是一个地址,通过这个地址可以找到luban这个对象
luban.sheJi() #通过对象去调用方法
houyi = Sheshou() #创建一个后裔
houyi.sheJi() #用这个实例出来的后裔对象 去调用sheji方法
#Sheshou.sheJi() #实例方法不能直接通过类去调用
# luban = Sheshou() #实例方法可以通过实例对象去调用
# luban.sheJi()
初始化方法是魔术方法之一, 所谓魔术方法就是在符合一定条件可以自动调用
class Sheshou:
"""射手类"""
def __init__(self): #初始化方法(魔术方法)
print("今天是个好日子")
luban = Sheshou() #实例化的过程就是这个类初始化的过程
#在实例化的时候 这个初始化的魔术方法会自动调用
实例方法,会隐含一个self参数,实例方法不属于类,属于实例。通过实例对象才能调用。
不能直接通过类去调用.
class Sheshou:
"""射手类"""
#行为(实例方法)
def sheJi(self):
print("我的攻击力是:{},防御能力是:{}".format(self.gongji,self.fanyu))
#只有实例化一个对象 才可以通过那个对象去调用实例方法
类属性是直接定义在类里面的变量,属于类本身。可以去访问它也可以去修改它
class Sheshou:
"""射手类"""
#类属性(变量)
gongji = 1700 #攻击力
fanyu = 300 #防御力
print(Sheshou.gongji) #访问
Sheshou.gongji = 1500 #修改
print(Sheshou.gongji)
#类属性可以之间通过类进行访问修改
实例属性不是直接定义在类的里面,通过初始化方法注入到类里面
class Sheshou:
"""射手类"""
def __init__(self,gongji,fangyu):
#初始化方法(魔术方法)
self.gongji = gongji #实例属性
self.fangyu = fangyu #实例属性
print("今天是个好日子")
print(Sheshou.gongji) #会报错 实例化属性不能直接通过类名去调用,必须通过实例化才能够访问它,修改它
#你得先实例一个对象出来 再通过实例对象去调用实例属性
class Sheshou:
"""射手类"""
#所谓魔术方法就是在符合一定条件可以自动调用
def __init__(self,gongji,fangyu):#初始化方法(魔术方法)
self.gongji = gongji #实例属性
self.fangyu = fangyu #实例属性
print("self是:{}".format(self))
luban = Sheshou(1200,100)
print("luban是:{}".format(luban)) print("\n====================================================\n")
houyi = Sheshou(600,180)
print("houyi是:{}".format(houyi))
#充足的证据证明self就是当前对象,当前实例化的对象是谁,那么self就指向谁
#当生成luban这个对象的时候 self当前就指向luban
#当生成houyi这个对象的时候 self当前就指向houyi
类方法属于类,不会隐含self,会隐含一个cls。
类方法需要使用@classmethod装饰器来进行修饰。
类方法可以直接通过类去调用,也可以被实例化对象调用。
class Cat:
"""猫类"""
def __init__(self,nickname,color):
self.nickname = nickname
self.color = color
@classmethod #@classmethod是一个装饰器,作用就是为这个方法添加一个额外的功能
def zhuaLaoShu(cls):
print("抓老鼠")
#直接通过类名调用
Cat.zhuaLaoShu() #会被成功调用,因为调用的对象是一个类方法 ,可以通过类进行直接调用
问题:类方法中能不能使用实例属性?
答案肯定是:不能。
# 原因:类方法的加载不需要实例化,初始化方法没有被调用。 实例属性就没来得及注入
静态方法需要使用@staticmethod来修饰
静态方法没有隐含任何参数,既可以实例化后通过对象去调用, 也可以直接被类调用。
静态方法不能访问类变量和实例变量,也不能使用self 要在类中使用静态方法,需在类成员函数前面加上@staticmethod标记符,以表示下面的成员函数是静态函 数。
使用静态方法的好处是,不需要定义实例即可使用这个方法。另外,多个实例共享此静态方法
(静态方法 无法访问类属性、实例属性,相当于一个相对独立的方法,跟类其实没什么关系,简单讲,静态方法就是放在 一个类的作用域里的函数而已。
静态方法的应用:抽取工具类
接下来请看如下案例:
我们先用面向对象写一个人机猜拳的游戏:
用户类:
class User:
"""用户类"""
#初始化方法,在实例化的时候自动调用
def __init__(self,userName):
self.userName = userName
#实例方法(普通方法)
def chuZhao(self):
uz = int(input("亲爱的{},请出招(1-剪刀 2-石头 3- 布):".format(self.userName)))
if uz == 1:
print("{}出招:剪刀".format(self.userName))
elif uz == 2:
print("{}出招:石头".format(self.userName))
else:
print("{}出招:布".format(self.userName))
return uz
电脑类:
class Computer:
"""用户类"""
# 初始化方法,在实例化的时候自动调用
def __init__(self, nickName):
self.nickName = nickName # 实例方法(普通方法)
def chuZhao(self):
import random cz = random.randint(1,3) #这边利用一个随机函数 随机生成(1-3)
if cz == 1:
print("{}出招:剪刀".format(self.nickName))
elif cz == 2:
print("{}出招:石头".format(self.nickName))
else:
print("{}出招:布".format(self.nickName))
return cz
进行比较:
from oop.人机猜拳.用户 import *
from oop.人机猜拳.电脑 import *
zs = User("小张") #实例化
xa = Computer("小爱同学") #实例化
u = zs.chuZhao() #通过对象去调用实例化方法
c = xa.chuZhao() #通过对象去调用实例化方法
if u == c:
print("平局")
elif u == 1 and c == 3 or u == 2 and c == 1 or u == 3 and c == 2:
print("{}胜利!".format(zs.userName))
else:
print("{}胜利!".format(xa.nickName))
这边我门可以利用静态方法去进行一个抽取
抽取出一个工具类
如上所述:
我们可以看到上诉代码有一些重复性的区域
这边进行一个抽取工具类的操作
工具类:
class Utils:
@staticmethod
def zhaoShi(name,zhao):
if zhao == 1:
print("{}出招:剪刀".format(name))
elif zhao == 2:
print("{}出招:石头".format(name))
else:
print("{}出招:布".format(name))
用户类:
from oop.人机猜拳.工具类 import *
class User:
"""用户类"""
#初始化方法,在实例化的时候自动调用
def __init__(self,userName):
self.userName = userName
#实例方法(普通方法)
def chuZhao(self):
uz = int(input("亲爱的{},请出招(1-剪刀 2-石头 3- 布):".format(self.userName)))
Utils.zhaoShi(self.userName,uz) #在此调用工具类的方法
return uz
电脑类:
from oop.人机猜拳.工具类 import *
class Computer:
"""用户类"""
# 初始化方法,在实例化的时候自动调用
def __init__(self, nickName):
self.nickName = nickName
# 实例方法(普通方法)
def chuZhao(self):
import random cz = random.randint(1,3)
Utils.zhaoShi(self.nickName,cz) #在此调用工具类的方法
return cz
对比类:
from oop.人机猜拳.用户 import *
from oop.人机猜拳.电脑 import *
zs = User("小张") #实例化
xa = Computer("小爱同学") #实例化
u = zs.chuZhao() #通过对象去调用实例化方法
c = xa.chuZhao() #通过对象去调用实例化方法
if u == c:
print("平局")
elif u == 1 and c == 3 or u == 2 and c == 1 or u == 3 and c == 2:
print("{}胜利!".format(zs.userName))
else:
print("{}胜利!".format(xa.nickName))
封装的概念
将类的属性或者方法私有化,不让外界直接访问,对外提供一个访问的接口。
提高数据的安全性。不用去管类 的具体细节,就可以获取类的实现接口,提高了开发的效率。
将类私有化!!!
只用在类属性或方法前加上__(两个下横杠即可)
class Woman:
"""女人类"""
#常识:女生的年龄是不能随意访问的
def __init__(self,name,age,weight):
self.name = name #姓名
self.__age = age #年龄 #私有化
self.weight = weight #体重
def show(self): print("我的名字叫:{},年芳:{},体重:斤".format(self.name,self.__age,self.weight))
binbin = Woman("冰冰",18,120)
#binbin.age = 190 #不能通过对象随意访问属性,数据不安全
binbin.age = 150 #私有化后,就不能随意访问和修改
binbin.name = "小凤"
binbin.show()
class Woman:
"""女人类"""
#常识:女生的年龄是不能随意访问的
def __init__(self,name,age,weight):
self.name = name #姓名
self.__age = age #年龄 私有化
self.weight = weight #体重
#定义set和get方法,是一个外界可以访问的接口
def setAge(self,age):#设置
#可以在这个方法里面加上业务逻辑,可以起到保护数据安全的作用
if age > 120 or age < 0:
age = 18
print("年龄不合法!年龄将自动设置为18岁")
else:
self.__age = age
def getAge(self): #定义一个获取 方法
return self.__age
def show(self):
print("我的名字叫:{},年芳:{},体重:{} 斤".format(self.name,self.getAge(),self.weight)) binbin = Woman("冰冰",18,120)
#binbin.age = 190 #不能通过对象随意访问属性,数据不安全
#binbin.age = 150 #私有化后,就不能随意访问和修改
binbin.name = "小凤"
binbin.setAge(220) #可以通过指定的接口访问
binbin.show()
#这边通过一个指定的 setAge()的接口 去获取年龄数据
再通过getAge()去返回一个年龄
子类继承父类,子类可以拥有父类的所有属性及所有方法。
这样可以大大提高代码的复用性。 java只支持单继承,或者是多层继承。 python支持多继承,多层继承
class Animal:
"""动物类"""
def __init__(self,name,sex):
self.name = name
self.sex = sex
def eat(self):
print("{}吃饭,性别:{}".format(self.name,self.sex))
def drink(self):
print("喝")
class Cat(Animal): #继承动物类
pass
class Dog(Animal): #继承动物类
pass
c = Cat("小肥猫","雌") #父类拥有的方法 子类也拥有
c.eat() #通过子类去调用父类的方法
d = Dog("旺财","雄")
d.eat()
class Animal:
"""动物类"""
def __init__(self,name,sex):
self.name = name
self.sex = sex
def eat(self):
print("{}吃饭,性别:{}".format(self.name,self.sex))
def drink(self):
print("喝")
class People:
def sing(self):
print("唱歌")
class Cat(Animal,People): #同时继承动物类 和People类
pass
class Dog(Animal,People): #同时继承动物类 和People类
pass
c = Cat("小肥猫","雌")
c.sing()
c.eat()
d = Dog("旺财","雄")
d.sing()
d.eat()
如果子类有一个与父类名相同的方法,则这个方法会被子类重写
class Animal:
"""动物类"""
def drink(self):
print("喝")
class fish(Animal):
"""鱼类"""
def drink(self): #子类重写父类的方法,父类的方法会被子类的方法覆盖
print("喝水")
c = fish()
c.drink()
#结果为喝水
class Animal:
"""动物类"""
def drink(self):
print("喝")
class fish(Animal):
"""鱼类"""
def drink(self):
super().drink() #子类拓展父类的方法,不会完全覆盖父类的方法,保留父类方法的同时,拓展 自己的业务
print("喝水")
这时候只需要加上一句 super()就行,这样子类只会扩展,而不会重写
多态的定义:不同的子类对象调用相同的方法产生不同的执行结果
多态使用前提:需要继承和对父类方法进行重写
多态的作用:一种接口多种实现,实现接口的重用
实现多态的步骤:
1,定义新的子类继承父类
2,重写对应的父类方法
3,使用子类的方法直接处理,不调用父类的方法
总结:不同的子类对象 使用同一个方法 结果输出需要的执行结果 -- 父类引用指向子类对象
在学校,铃声响起的时候,对于学生来说是放学,对于老师是下班
class School:
"""学校"""
def music(self):
print("打铃")
class Student(School):
def music(self):
print("铃声响起,放学了")
class Teacher(School):
def music(self):
print("铃声响起,下班了")
s = Student() #实例化出一个学生对象
t = Teacher() #实例化一个老师出来
def jiekou(obj): #传入学生对象,实现学生的业务。传入老师,实现老师的业务。同一个接口,不同实现
obj.music()
jiekou(t) #通过不同的参数 产生不同的结果 #传入老师 就是老师的music()方法
#传入学生 就是学生的music()的方法