类的一些理论概念及其应用场景等基础内容此处不赘述
目录
类的定义及基础
属性
方法
初始化方法
普通方法
类之间的关系
相互调用
依赖关系
关联关系
组合关系
三大特征----类的继承
重写父类方法
多继承
三大特征----封装
三大特征----多态
类的定义及基础
类的一般定义:
class Name_of_Class:
Shared_property=1
def __init__(self):
private_property=2
def method(self):
print(1)
类里包含了属性和方法
属性
属性分为公共属性和实例属性,上面的shared_property就是共有属性,private_property就是实例属性,区别在于:
公有属性是放在原始类的内存中的,如果发生改变,所有对象都会发生改变
私有属性是放在对象内存中的,如果改变只会改变该对象的值,是对象独享的
举个例子
class Name_of_Class:
Shared_property=1
def __init__(self):
self.object_property=2
obj1=Name_of_Class()
obj2=Name_of_Class()
Name_of_Class.Shared_property=111
print(obj1.Shared_property)
print(obj2.Shared_property)
obj1.object_property=3
print(obj2.object_property)
# 111
# 111
# 2
那比如要设置一个 某个年级学生信息的类,就可以把 年级 作为公共属性,把一些身高体重等作为实例属性
但是如果对象把类的公共属性给改了,就相当于给对象创建了一个新的实例有属性
class Name_of_Class:
Shared_property=1
obj1=Name_of_Class()
obj2=Name_of_Class()
obj1.Shared_property=111
print(obj1.Shared_property)
print(obj2.Shared_property)
# 111
# 1
方法
初始化方法
def __init__(self):
pass
又叫做构造方法,构造函数,实例化的时候会自动运行
初始化方法可以设置参数,一般的格式是
class Name_of_Class:
Shared_property=1
def __init__(self,object_property1,object_property2):
self.object_property1=object_property1
self.object_property2=object_property2
调用方式是
obj1=Name_of_Class(2,3)
print(obj1.object_property1)
print(obj1.object_property2)
# 2
# 3
在进行实例化的时候直接传参就可以调用初始化方法
这里的self.object_property1=object_property1是确保将传进来的参数作为对象本身的实例属性保存起来,这里借用一张内存图说明
- 实例化时,申请一块内存空间
- 将实例化的参数传给__init__
- __init__将参数转为实例属性传给这个内存空间
普通方法
class Name_of_Class:
Shared_property=1
def __init__(self,object_property1,object_property2):
self.object_property1=object_property1
self.object_property2=object_property2
def method(self):
print(self.object_property2+self.object_property1)
obj1=Name_of_Class(2,3)
obj1.method()
# 5
普通方法的参数同一有 self ,告知是哪个对象调用了方法
在普通方法中调用私有参数要 self.xxxx
类之间的关系
相互调用
只需要在定义类方法的时候将其他的对象作为参数传进去
class soilder:
def __init__(self,name,m4):
self.name=name
self.m4=m4
self.bloodall=100
def attack_back(self,badperson):
badperson.bloodall-=self.m4
print('soilder [%s] attack badperson [%s],badperson has [%s] blood'%(self.name,badperson.name,badperson.bloodall))
class badperson:
def __init__(self, name, ak):
self.name = name
self.ak = ak
self.bloodall = 100
def attack(self, soilder):
soilder.bloodall -= self.ak
print('badperson [%s] attack soilder [%s],soilder has [%s] blood'%(self.name,soilder.name,soilder.bloodall))
lee = soilder('lee',30)
liu =badperson('liu',35)
liu.attack(lee)
lee.attack_back(liu)
# badperson [liu] attack soilder [lee],soilder has [65] blood
# soilder [lee] attack badperson [liu],badperson has [70] blood
依赖关系
在依赖类的 初始化函数 中将master对象引入
class dog:
def __init__(self,name,age,master):
self.name=name
self.age=age
self.master=master
def say(self):
print('my master is ',self.master.name)
class master:
def __init__(self, name, age):
self.name = name
self.age = age
p1 = master('lee',23)
d1=dog('hhh',2,p1)
d1.say()
关联关系
这个通过一个例子来说明这种关系,生活中最常见的这种关系是 结婚
结婚是两个人一起结婚的,所以在这里最好定义一个新的类relationship来存储两个人的婚姻关系,这样可以保证避免了A和B结婚了但是B和A没结婚的bug出现
如果结婚了就调用get_marred函数,如果离婚就是diverse函数,状态存储在couple数组里面
person类中调用这个relation类进行操作,并且可以通过get_partner函数获取自己的伴侣
class relationship:
def __init__(self):
self.couple=[]
def get_married(self,obj1,obj2):
self.couple=[obj1,obj2]
print(obj1.name,'and ',obj2.name,'get married')
def diverse(self):
self.couple=[]
class person:
def __init__(self,name,age,sex,relation):
self.name=name
self.age=age
self.sex=sex
self.relation=relation
def get_partner(self):
for i in self.relation.couple:
if i.name==self.name:
continue
else:
return i.name
relationship_obj=relationship()
p1=person('lee',23,'M',relationship_obj)
p2=person('liu',22,'F',relationship_obj)
relationship_obj.get_married(p1,p2)
print(p2.get_partner())
relationship_obj.diverse()
print(p1.get_partner())
# lee and liu get married
# lee
# None
组合关系
由一堆组件构成一个整体,组件自己独立但是不能自己运行,必须跟宿主结合,例如人的器官和人的关系
这里定义了一个器官类,里面有不同器官的函数
在定义person类时,直接 self.action=organs(),既实例化一个器官对象,那么每次实例化一个person都会实例化一个organs,器官和人就是组合关系
class organs:
def __init__(self):
self.name=None
def heart(self):
self.name = '心脏'
print('心脏跳动了一下')
def lung(self):
self.name='肺'
print('肺呼吸了一下')
class person:
def __init__(self,name,age,sex):
self.name=name
self.age=age
self.sex=sex
self.action=organs()
def get_partner(self):
for i in self.relation.couple:
if i.name==self.name:
continue
else:
return i.name
p1=person('lee',23,'M')
p2=person('liu',22,'F')
p1.action.heart()
p1.action.lung()
# 心脏跳动了一下
# 肺呼吸了一下
三大特征----类的继承
类的继承是三大特征之一,主要的功能是使类A能得到类B的所有方法和属性而不需要重复书写代码,继承的方式就是在定义的时候加入父类的名字:
class son(father):
pass
例如猪和人都是动物,那么可以抽象一个animal类,把动物该有的属性和方法加入,当然新定义的类也可以加入自己独有的方法,或者重构 原有父类的方法:
class animal:
def __init__(self,name,age,sex):
self.name=name
self.age=age
self.sex=sex
def eat(self):
print(111)
class pig(animal):
pass
class person(animal):
def eat(self):
print(333)
def thinking(self):
print(222)
p1 = pig('liu',2,'M')
p2 = person('lee',23,'F')
p1.eat()
p2.thinking()
p2.eat()
# 111
# 222
# 333
重写父类方法
新定义的类也可以在原有类的基础上增加功能,而不完全重构
下面的代码在person继承了animal类,并且增加了初始化函数和普通方法的功能,主要思想就是在定义新的类的方法使,先运行父类的方法
class animal:
def __init__(self,name,age,sex):
self.name=name
self.age=age
self.sex=sex
def eat(self):
print(111)
class person(animal):
def __init__(self,name,age,sex,hobby):
animal.__init__(self,name,age,sex)
self.hobby=hobby
def eat(self):
animal.eat(self)
print(333)
def thinking(self):
print(222)
p2 = person('lee',23,'F','study')
print(p2.hobby)
p2.eat()
# study
# 111
# 333
在高版本的python中,还支持这种写法,其实结果是一样的:
class person(animal):
def __init__(self,name,age,sex,hobby):
super(person,self).__init__(name,age,sex)
# animal.__init__(self,name,age,sex)
self.hobby=hobby
def eat(self):
super(person, self).eat()
print(333)
def thinking(self):
print(222)
或者
class person(animal):
def __init__(self,name,age,sex,hobby):
super().__init__(name,age,sex)
# animal.__init__(self,name,age,sex)
self.hobby=hobby
def eat(self):
super().eat()
print(333)
def thinking(self):
print(222)
多继承
python是允许多继承的,也就是可以同时继承多个父类
当父类也有父类时,就有一个树状结构,此时继承顺序就很重要,这里有一个简单的例子
例如下面这种情况,同时继承了两个类,按照从左到右的顺序继承
class father(grandpa):
def test(self):
print('father')
class mother:
def test(self):
print('mother')
class son(father,mother):
pass
p1=son()
p1.test()
#fatehr
再例如,当father类没有test时,会搜索father的父辈grandpa:
class grandpa:
def test(self):
print('grandpa')
class father(grandpa):
pass
class mother:
def test(self):
print('mother')
class son(father,mother):
pass
p1=son()
p1.test()
#grandpa
到这里为止,都很像深度优先搜索,但是其实不是,而是运用了C3算法,比如当fater和mather类都继承自grandpa时:
class grandpa:
def test(self):
print('grandpa')
class father(grandpa):
pass
class mother(grandpa):
def test(self):
print('mother')
class son(father,mother):
pass
p1=son()
p1.test()
# mother
为了方便,可以直接查看类的继承顺序
print(son.mro())
#[<class '__main__.son'>, <class '__main__.father'>, <class '__main__.mother'>, <class #'__main__.grandpa'>, <class 'object'>]
至于C3算法,有兴趣的可以看看这个
Python 中多继承 C3-MRO 算法的剖析 - 知乎
三大特征----封装
封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。
要访问该类的代码和数据,必须通过严格的接口控制。
封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。
适当的封装可以让程式码更容易理解与维护,也加强了代码数据的安全性。
比如一个这样的例子,人在银行的财产只能通过一些方法改变,例如存钱和取钱,如果按照普通的定义:
class person_bank:
def __init__(self,name):
self.money=0
p1=person_bank('lee')
p1.money=100
print(p1.money)
# 100
这样其实是不安全的,因为外部谁都可以自由的修改money的值
这里引入私有属性的概念,其实就是使得外部不能访问,但是在类里面是可以访问的,只需要在变量前加 __
class person_bank:
def __init__(self,name):
self.__money=0
def get_money(self,num):
self.__money=self.__money+num
def check(self):
print(self.__money)
p1=person_bank('lee')
p1.check()
p1.get_money(100)
p1.check()
# 0
# 100
那么将私有属性放入类方法中修改的这种模式就叫做封装
当然方法也可以变为私有方法
class person_bank:
def __init__(self,name):
self.__money=0
def __interest(self):
self.__money=self.__money+1
p1=person_bank('lee')
p1.__interest()
# 'person_bank' object has no attribute '__interest'
但是其实私有属性和方法也不是完全不能外部访问的,也可以用下面这种方法破解
也就是 实例名._类名+方法名
print(p1._person_bank__money)
p1._person_bank__interest()
三大特征----多态
有时一个对象会有多种表现形式,比如网站页面有个button按钮,这个button的设计可以不一样(单选框、多选框、圆角的点击按钮、直角的点击按钮等),尽管长的不一样,但它们都有一个共同调用方式,就是onClick()方法。我们直要在页面上一点击就会触发这个方法。点完后有的按钮会变成选中状态、有的会提交表单、有的甚至会弹窗。这种多个对象共用同一个接口,又表现的形态不一样的现象,就叫做多态( Polymorphism )。
通过统一接口实现多态:
其实就是封装一个函数,调用不同类的同名方法
class one:
def test(self):
print(1)
class two:
def test(self):
print(2)
def gettest(obj):
obj.test()
a=one()
b=two()
gettest(a)
gettest(b)
通过抽象类实现多态
class num:
def test(self):
# 可以继承,但是必须自己定义一个新的
raise NotImplementedError('自己定义')
class one(num):
def test(self):
print(1)
class two(num):
def test(self):
print(2)
a=one()
b=two()
objs=[a,b]
for i in objs:
i.test()