面向对象编程
何谓面向对象编程?解释起来不是那么容易,但是肯定不是面向姑娘编程,嘿嘿。OOP(Object Oriented Programing)编程是利用“类”和“对象”来创建各种模型来实现对真实世界的描述。我们要了解面向对象编程的话,我们可以站在造物主——上帝的角度来看待这个问题。这里引用一个来自他人的例子,帮助我们理解:
如果你是上帝,你现在要创世纪,把这么多人、动物、山河造出来,上帝光靠自己干,一个一个的造人,多累呀,让你干这个活,你肯定是先造模子,一个男人模子,一个女人模子,剩下的就一个个复制就行啦。这个模子的作用是什么?模子定义了人这个物种所具备的所有特征\(或者说,我们把具备这些特征的个体归为人类\)。这个世界上所有的东西都是你定义的,你需要用最高效的方式去造世界,最高效的方式就是,先把世界按物种、样貌、有无生命等各种维度分类,然后给每类东西建模型,再让其在不脱离你基本横型定义的框架下,自我繁衍(世界要多姿多彩,所以即使是同一物种,也要有些不一样)
为什么使用面向对象:
- 使程序更加容易扩展和易更改,使开发效率变的更高
- 基于面向对象的程序可以使它人更加容易理解你的代码逻辑,从而使团队开发变得更从容
面向对象的一些名词解释
类:一个类即是对一类拥有相同属性的对象的抽象、蓝图、原型、模板。在类中定义了这些对象的都具备的属性(variables(data))、共同的方法
属性:人类包含很多特征,把这些特征用程序来描述的话,叫做属性,比如年龄、身高、性别、姓名等都叫做属性,一个类中,可以有多个属性
方法:人类不止有身高、年龄、性别这些属性,还能做好多事情,比如说话、走路、吃饭等,相比较于属性是名词,说话、走路是动词,这些动词用程序来描述就叫做方法。
实例(对象):一个对象即是一个类的实例化后实例,一个类必须经过实例化后方可在程序中调用,一个类可以实例化多个对象,每个对象亦可以有不同的属性,就像人类是指所有人,每个人是指具体的对象,人与人之前有共性,亦有不同
实例化:把一个类转变为一个对象的过程就叫实例化
接下来上一段代码来解释一些我们在实际写代码的时候对于这些名词的解释,以便更好地了解:
#__init__方法用来为对象定制对象自己独有的特征
class LuffyStudent:
school='luffycity' 这里是类的数据属性
# stu1, '王二丫', '女', 18
def __init__(self,name,sex,age):
self.Name=name
self.Sex=sex
self.Age=age
#stu1.Name='王二丫'
#stu1.Sex='女'
#stu1.Age=18
def learn(self):
print('is learning')
def eat(self):
print('is sleeping')
#后产生对象
stu1=LuffyStudent('王二丫','女',18) #LuffyStudent.__init__(stu1,'王二丫','女',18)
#加上__init__方法后,实例化的步骤
# 1、先产生一个空对象stu1
# 2、LuffyStudent.__init__(stu1,'王二丫','女',18) self就是我们的对象stu1
#查
print(stu1.__dict__)
#print(stu1.Name)
#print(stu1.Sex)
#print(stu1.Age)
#改
# stu1.Name='李二丫'
# print(stu1.__dict__)
# print(stu1.Name)
#删除
# del stu1.Name
# print(stu1.__dict__)
#
# #增
# stu1.class_name='python开发'
# print(stu1.__dict__)
我们实例化的对象的属性其实就是一个字典的形式来保存的,因此可以进行增删改查的操作
__init__(...)
被称为 构造方法或初始化方法,在例实例化过程中自动执行,目的是初始化实例的一些属性。每个实例通过__init__初始化的属性都是独有的,具体步骤见上方代码。
关于面向对象的具体操作
下面是一个实例说明
#可拓展性高
class Student:#先定义一个类
country = 'china'
count = 0
def __init__(self,name,age,sex):#析构函数,这里传4个参,self就是stu1
self.Name = name
self.Age = age
self.Sex = sex
Student.count += 1#在析构函数中未定义,变向类属性中去找count,因此修改的就是大家的属性,不是独自的
stu1 = Student('Marvelous',22,'man') #实例化一个对象
stu2 = Student('Tom',23,'man') #实例化一个对象
stu3 = Student('West',21,'man') #实例化一个对象
# print(stu1.__dict__)
print('产生了%s个学生'%Student.count) #属性都可以用
一些补充:
函数属性是针对对象的,不同的对象的函数内容不同
一切皆对象--
------------------------------------------------------分割线--------------------------------------------------
为了引出继承和重用这两个家伙,我们上一段冗余的交互型面向对象代码
#定义两个类,使两个类进行交互
class Garlen:
country = 'demaciya'
def __init__(self,nickname,life_value,aggresivity):
self.nickname = nickname
self.life_value =life_value
self.aggresivity = aggresivity
def attack(self,other):
self.life_value -= other.aggresivity
class Draven:
country = 'NOXAS'
def __init__(self, nickname, life_value, aggresivity):
self.nickname = nickname
self.life_value = life_value
self.aggresivity = aggresivity
def attack(self, other):
self.life_value -= other.aggresivity
person1 = Garlen('大宝剑',100,50)
person2 = Draven('Vincent',100,80)
person1.attack(person2)
print(person1.life_value)
#就类似与方法的调用,从某种方面来说,就印证了一句话,python中一切皆对象!!!
继承不会缺席,只会迟到,话不多说,上图:
说完继承再来个派生
子类中重用父类的方法,话不多说,上代码
# 在子类派生出的新的方法中重用父类的方法,有两种实现方式
# 方式一:指名道姓(不依赖继承)
# 方式二:super() (依赖继承)
class Hero:
def __init__(self,nickname,life_value,aggresivity):
self.nickname=nickname
self.life_value=life_value
self.aggresivity=aggresivity
def attack(self,enemy):
enemy.life_value-=self.aggresivity
class Garen(Hero):
camp='Demacia'
def attack(self,enemy):
Hero.attack(self,enemy) #指名道姓
print('from Garen Class')
加红部分就是不依赖继承的指名道姓的方式
接下来介绍依赖继承的super方法:
class A:
def f1(self):
print('----A----')
super().f1()
class B:
def f1(self):
print('----B----')
class C(A,B):
pass
print(C.mro())
# super的继承顺序⬇,
# [<class '__main__.C'>,
# <class '__main__.A'>,
# <class '__main__.B'>,
# <class 'object'>]
stu1 =C()
stu1.f1()
在上述代码中,super的继承顺序是基于C.mro()这个列表数据类型的元素来实现的,从左到右的查找方式,因为B在A右边,所以输出的结果如下:
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
----A----
----B----
面向对象之组合
#解决代码重用的方案:
#1.从属关系的时候我们可以使用继承
#2平行关系的时候可以直接调用其他类的东西
#需求:学生,老师,课程,时间
class People:
school = 'luffyCity'
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
#定义了人的基本属性,后面学生和老师可以使用
class Teacher(People):
'''老师'''
def __init__(self,name,age,sex,level,salary):
super().__init__(name,age,sex)
self.level = level
self.salary =salary
def leran(self):
print('%s is learn...'%self.name)
class Student(People):
'''学生类'''
def __init__(self,name,age,sex,class_name,):
super().__init__(name,age,sex)
self.class_name =class_name
def leran(self):
print('%s is learn...'%self.name)
class Course:
'''课程类'''
def __init__(self,course_name,money,cost_time):
self.course_name = course_name
self.money =money
self.cost_time =cost_time
def course_info(self):
'''课程介绍'''
print('课程名称<%s> 价格<%s> 周期<%s>'%(self.course_name,self.money,self.cost_time))
teacher1 =Teacher('Marvelous','22','man','s1','500W')
python = Course('pyhton','8999','6mon')
teacher1.course = python#先给变量赋值,再进行相关操作
teacher1.course.course_info()#==python.course_info()
python.course_info()
大体操作就在⬆里面了,嘻嘻嘻
接下来介绍关于面向对象的三大特性:继承,封装,多态
继承详情请往上翻阅
那么接下来就是封装
下面是封装的隐藏
class A:
__x = '你好'
def talk(self):
print('talk is cheap!')
self.__show()
def __show(self):
print('是时候表演真正的技术了!')
class B(A):
def speak(self):
self._A__show()#同理,子类继承的时候如果直接用__show()也是不行的
man1 = A()
girl1 =B()
# man1.__x 该方式无法调用类的属性,因为实际上我们的类已经变成了_A__x l了,即实现了属性的隐藏
print(man1._A__x)
man1._A__show()#同理类中的函数的调用也是如此
man1.talk()#但是在内部调用的时候还是像普通调用的时候一样,所以这个隐藏过程是在内部实现的过程中完成的
girl1.speak()
'''
综上所述:⬇
这种变形的特点:
1、在类外部无法直接obj.__AttrName
2、在类内部是可以直接使用:obj.__AttrName
3、子类无法覆盖父类__开头的属性
'''
然后我们来了解一下封装的意义:
#一、封装数据属性:明确的区分内外
class A:
def __init__(self,name,age):
self.__name = name
self.__age =age
def show(self):
print('我叫<%s>,今年<%s>岁'%(self.__name,self.__age))
def set_info(self,name,age):
self.__name = name
self.__age =age
m1 = A('周栩强','22') #实例化之后再调用方法
m1.set_info('Marvelous','22') #给一个接口使得所有内容在接口处完成,不需要再在里面去修改具体的内容
m1.show()
#二、封装方法:分离复杂度
class Lol:
def __login(self):
print('请输入账号与密码:')
def __welcome(self):
print('欢迎来到英雄联盟!')
def __choose(self):
print('请选择您的英雄:')
def __loading(self):
print('欢迎来到召唤师峡谷!')
def __start(self):
print('英雄,去超越!')
def main(self):#一个接口解决了一系列的操作,从而降低复杂度,就像一系列的步骤组成一个完整的活动
self.__login()
self.__welcome()
self.__choose()
self.__loading()
self.__start()
z1 = Lol()
z1.main()
接下来是多态时间:
#多态:同一类事物的多种形态
import abc
class Animal(metaclass=abc.ABCMeta): #同一类事物:动物
@abc.abstractmethod
def talk(self):
pass
class People(Animal): #动物的形态之一:人
def talk(self):
print('say hello')
class Dog(Animal): #动物的形态之二:狗
def talk(self):
print('say wangwang')
class Pig(Animal): #动物的形态之三:猪
def talk(self):
print('say aoao')
class Cat(Animal):
def talk(self):
print('say miamiao')
#多态性:指的是可以在不考虑对象的类型的情况下而直接使用对象
peo1=People()
dog1=Dog()
pig1=Pig()
cat1=Cat()
# peo1.talk()
# dog1.talk()
# pig1.talk()
def func(animal):
animal.talk()
func(peo1)
func(pig1)
func(dog1)
func(cat1)