Python面向对象编程(一)类的基础,关系,继承,封装,多态

类的一些理论概念及其应用场景等基础内容此处不赘述

目录

类的定义及基础

属性

方法

初始化方法

 普通方法

类之间的关系

相互调用

依赖关系

关联关系

组合关系

三大特征----类的继承

重写父类方法

多继承

三大特征----封装

三大特征----多态


类的定义及基础

类的一般定义:

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是确保将传进来的参数作为对象本身的实例属性保存起来,这里借用一张内存图说明

Python面向对象编程(一)类的基础,关系,继承,封装,多态_第1张图片

  1.  实例化时,申请一块内存空间
  2. 将实例化的参数传给__init__
  3. __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())
#[, , , , ]

至于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()

你可能感兴趣的:(Python天下第一,python,开发语言)