python面向对象之封装、继承与多态

本文介绍了面向对象编程的基本概念,包括类与对象的定义,数据属性与实例属性的区别,类的封装以及方法重写。详细阐述了Python中的类方法、实例方法、静态方法和类方法,以及单继承和多继承的概念,同时探讨了方法解析顺序(MRO)和多态性在编程中的应用。
摘要由CSDN通过智能技术生成

目录

面向对象程序设计

类和对象

属性查找

 数据属性

实例属性 

类的封装

封装数据

封装⽅法(隔离复杂度)

类的⽅法

类的继承 

继承概述

单继承

多继承

⽅法重写

继承原理

深度优先&⼴度优先

类的内置⽅法

类的多态

多态性


面向对象程序设计

所谓编程范式,就是程序员使⽤特定的语法+数据结构和算法编写代码,最终的⽬的是告诉计算机来解析并且来执⾏这些代码。在编程范式的领域,主要分为⾯向过程的编程⽅式和⾯向对象的编程⽅式,具体如下:
        ⾯向过程,也就是说流程化的⼲⼀件事,严格的按照顺序来进⾏,很明显,这与⽬前的敏捷模式格格不⼊的。但是它也是具备优点的,它的优点是把复杂的问题流程化,进⼀步达到简单化的过程。所谓优点也是缺点,在这⾥体现的⾮常明显,正因为对进⾏了流程化,也就导致了⼀套流程只能解决⼀个问题,⽐如⽣产汽⻋的流⽔线等,它的可扩展性存在很⼤的缺陷,因此也级有了⾯向对象的编程⽅式。
        ⾯向对象的编程,在上帝的视⻆下,来审视万事万物,⼀切皆是对象。与⾯向过程的机械式的编程⽅式⽽⾔,⾯向对象的编程⽅式更加看重的是对象,⽽⾮过程,它的优点具体为:解决了⾯向过程可扩展性的问题,在软件的⻆度⽽⾔,⾯向对象的程序设计只是来解决程序扩展性的问题

类和对象

所谓类就是类别,类简单的理解就是⼀系列对象相似的特征与技能的结合体。⽐如我们定义⼀个⼈的类,那么⾥⾯的⽅法就是⼈的特征。在程序⾥⾯,需要特别强调的是先定义类,再使⽤类(对类进⾏实例化)。在Python中,定 义类的关键字是class,所有类的基类是object。如下定义⼀个⼈的类,具体如下:

class Person(object):
   def __init__(self,name,age):
      self.name=name
      self.age=age

定义类的时候得切记,类的⾸字⺟是⼤写的,我们要使⽤⼀个类,我们就需要对它进⾏实例化,具体如下: 

class Person(object):
   def __init__(self,name,age):
      self.name=name
      self.age=age
      
if __name__ == '__main__': 
   person=Person(name='⽆涯',age=18)

在如上的案例中,person就是类Person()的实例化后的对象,我们使⽤对象就可以查看对象的内存空间的信息,如: 

class Person(object): 
   '''基于⼈的定义'''
    def __init__(self,name,age):
       self.name=name
       self.age=age
   
if __name__ == '__main__': 
   person=Person(name='xcj',age=18) 
   print(person.__dict__)

输出:
{'name': '⽆涯', 'age': 18}

属性查找

在类中,关于属性主要分为数据属性实例属性,下⾯结合具体的案例来说明下这部分。具体案例代码如下:

class Person(object):
   '''基于⼈的定义'''
   country='中国'
   city='⻄安'
   def __init__(self,name,age):
      self.name=name
      self.age=age
if __name__ == '__main__':
   person=Person(name='xcj',age=18)

 数据属性

类的数据属性是针对所有对象共享的,也就是说针对⼀个类进⾏实例化后的对象,调⽤数据属性它的内存地址都是⼀样的,如下:

class Person(object): 
   '''基于⼈的定义''' 
   country='中国' 
   city='⻄安'
   
   def __init__(self,name,age):
      self.name=name
      self.age=age
      
if __name__ == '__main__': 
   p1=Person(name='xcj',age=18) 
   p2=Person(name='xyz',age=19) 
   #内存地址一致
   print(id(p1.country)) 
   print(id(p2.country))
   #内存地址不一致
   print(id(p1.name))
   print(id(p2.name))

执⾏后,输出的内存地址是⼀致的。类的数据属性是绑定对象的。在如上中,p1.country中,它寻找的顺序是⾸先在p1的命名空间⾥⾯去找country, 如果找不到就去类⾥⾯找,类⾥⾯如再不到,就到基类⾥⾯去找,最后找不到,就会抛出对应的错误信息。具体如下:

class Person(object):
   '''基于⼈的定义'''
   country='中国'
   city='⻄安'
   def __init__(self,name,age):
      self.name=name
      self.age=age
if __name__ == '__main__':
   p1=Person(name='xcj',age=18)
   print(p1.address)
Traceback (most recent call last):
File "/Applications/code/Yun/zeroTestDev/demo.py", line 17, in <module>
print(p1.address)
AttributeError: 'Person' object has no attribute 'address'

实例属性 

下⾯来看实例属性,具体如下涉及到的案例代码为:

class Person(object):
   '''基于⼈的定义'''
   def __init__(self,name,age):
      self.name=name
      self.age=age
   def show(self):
      print('my name is {0},and age is {1}'.format(self.name,self.age))
if __name__ == '__main__':
   p1=Person(name='xcj',age=18)
   p1.show()

在类⾥⾯定义的属性name,age我们成为实例属性,但是定义的时候必须遵守函数的形式参数的规则,有⼏个参数就需要传⼏个,如下⾯案例少传⼀个,具体案例源码为:

class Person(object):
   '''基于⼈的定义'''
   def __init__(self,name,age):
      self.name=name
      self.age=age
   def show(self):
      print('my name is {0},and age is {1}'.format(self.name,self.age))
if __name__ == '__main__':
   p1=Person(name='xcj')
   p1.show()


执⾏后就会显示如下的错误信息:
Traceback (most recent call last):
File "/Applications/code/Yun/zeroTestDev/demo.py", line 15, in <module>
p1=Person(name='xcj')
TypeError: __init__() missing 1 required positional argument: 'age'

类的封装

在Python中,封装的特性是通过数据属性与实例属性来进⾏体现的。封装的核⼼本质思想是针对类内部的属性进⾏封装(隐藏)。

封装数据

在类的内部把数据隐藏起来,对外提供⼀个接⼝来操作具体的数据,然后在基础上增加对数据操作的权限和判断,具体案例代码如下:

class Person(object):
   def __init__(self,name,age):
      self.name=name
      self.age=age
   def info(self):
      print('my name is {name},and my age is {age}'.format(
         name=self.name,age=self.age))
   def setInfo(self,name,age):
      if  not isinstance(name,str):
         raise TypeError('name不是字符串的数据类型')
      if not isinstance(age,int):
         raise TypeError('age不是整型的数据类型')
      self.name=name
      self.age=age
if __name__ == '__main__':
   person=Person('xcj','18')
   person.setInfo('name','10')
   person.info()

程序执⾏后,就会报如下的错误信息,具体错误信息如下:

raise TypeError('age不是整型的数据类型')
TypeError: age不是整型的数据类型

封装⽅法(隔离复杂度)

在实际的⼯作中,业务操作的复杂度是⾮常高的,这样我们可以根据业务的形态针对⽅法进⾏封装,这样对外调⽤起来会更加的简单,具体如下:

class HomePage():
   def login(self):
      pass
   
   def order(self):
      pass
   
   def getOrder(self):
      self.login()
      self.order()

在如上的业务形态中,最终的⽬的是查看订单的信息,但是查看订单的前提是⾸先需要先登录,所以我们可以针对业务的具体诉求进⾏封装

类的⽅法

在Python的类⾥⾯,在类⾥⾯编写的特性函数称为⽅法,这些⽅法主要分为普通⽅法特性⽅法静态⽅法类⽅法,具体如下:

class Person(object):
   '''基于⼈的定义'''
   def __init__(self,name,age):
      self.name=name
      self.age=age

   def show(self):
      print('my name is {0},and age is {1}'.format(self.name,self.age))

   @property
   def info(self):
      print('我是特性⽅法')

   @staticmethod
   def eat():
      print('⼈每天都需要吃饭')

   @classmethod
   def driver(cls): print('我是类⽅法')

if __name__ == '__main__':
   person=Person(name='xcj',age=18)
   person.show()
   person.info
   Person(name='xcj',age=18).eat()
   person.driver()

普通⽅法:属于对象也属于类
特性⽅法:属于对象,编写特性⽅法的使⽤需要特别注意,该⽅法不能有形式参数,具备只读属性
静态⽅法:属于类,使⽤类名直接调用

@staticmethod 静态⽅法只是名义上归属类管理,但是不能使⽤类变量和实例变量,是类的⼯具包
放在函数前(该函数不传⼊self或者cls),所以不能访问类属性和实例属性

类⽅法:属于类,使⽤类名直接可以调⽤ 

类的继承 

在Python⾥⾯,⼀个类是可以继承多个类的。我们可以把类的继承理解为类与类之间的关系,在Python3⾥⾯,类的继承使⽤的算法是MRO的算法。在继承中,继承的类叫⼦类或者派⽣类,被继承的类称为基类或者是⽗类。具体如下:

class Person(object):
   '''基于⼈的定义'''
   def __init__(self,name,age):
      self.name=name
      self.age=age

   def show(self):
      print('my name is {0},and age is {1}'.format(self.name,self.age))

class Worker(Person):

   def __init__(self,name,age,salary):
      super().__init__(name,age)
      self.salary=salary

   def info(self):
      print('姓名{0},年龄:{1},薪资:{2}'.format(self.name,self.age,self.salary))

if __name__ == '__main__':
   worker=Worker(name='xcj',age=18,salary=1000)
   worker.info()
   worker.show()

⾸先需要明确的是,⼀个⼦类继承⽗类,是继承⽗类⾥⾯所有的实例属性和⽅法,以及类属性的,具体结合如下案例来查看源码:

class Person(object):
    '''基于⼈的定义'''
    city = '陕⻄省⻄安市'

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def show(self):
        print('my name is {0},and age is {1}'.format(self.name, self.age))


class Worker(Person):

    def __init__(self, name, age, salary):
        super().__init__(name, age)
        self.salary = salary

    def info(self):
        print('姓名{0},年龄:{1},薪资:{2},城市:{3}'.format(self.name, self.age, self.salary, self.city))


if __name__ == '__main__':
    worker = Worker(name='xcj', age=18, salary=1000)
    worker.info()
    worker.show()

继承概述

⾯向对象三⼤特性分别是封装,继承,多态。所谓继承其实就是类与类之间的关系,⽽继承的⽬的就是为了解决代码重⽤问题,所以继承在某些⽅⾯来说,它是⼀种创建新类的⽅式,在Python中,⼀个类可以继承⼀个类,也可以继承多个类。被继承的类被称为:基类,继承别⼈的类,被称为:派⽣类。如下案例,具体如下:

class Person(object):
   pass
class Student(Person):
   pass

查看继承的⽅式是使⽤bases,也就是查看⼦类继承的所有的⽗类,具体如下:

class Person(object):
    pass

class Student(Person):
    pass

if __name__ == '__main__':
    print(Student.__bases__)


执⾏如上的代码后,输出的结果信息为:
(<class '__main__.Person'>,)

继承多个类,具体如下:

class Person(object):
    pass

class Animal(object):
    pass

class Student(Person, Animal):
    pass

if __name__ == '__main__':
    print(Student.__bases__)

执⾏代码后,输出的结果信息:
(<class '__main__.Person'>, <class '__main__.Animal'>)

特别注意:⼦类可以继承⽗类所有的⽅法以及属性。

单继承

在Python中,针对类的继承,可以使⽤单个类的继承,也可以使⽤多个类的继承,下⾯我们先来看单个类的继承。

class Person(object):
   country='中国'
   def __init__(self,sex):
      self.sex=sex
   def show(self):
      print('来⾃那个{0},性别是:{1}'.format(self.country,self.sex))

class ManStudent(Person):
   def __init__(self,sex,score):
      Person.__init__(self,sex)
      self.score=score
if __name__ == '__main__':
   student=ManStudent('男',90.9)
   student.show()

执⾏后,就可以看到⼦类继承了⽗类的所有属性。

多继承

多继承更多指的是在Python⾥⾯,⼀个类可以继承多个类,那么就会涉及到⼀个调⽤的优先级的顺序问题。这个顺序问题具体可以有两种⽅式,第⼀种是从左到右的原则,第⼆种是从下到上的原则。

#从左到右
class Father(object):
   def __init__(self,sex):
      self.sex=sex
   def show(self):
      print('我是爸爸')
class Mother(object):
   def __init__(self,sex):
      self.sex=sex
   def show(self):
      print('我是妈妈')
class Son(Father,Mother):
   def __init__(self,sex,school):
      super().__init__(sex)
      self.school=school
if __name__ == '__main__':
   son=Son(sex='男孩⼦',school='⻄安第⼀中学')
   son.show()

在⼀个⼦类⾥⾯,⼦类继承了多个⽗类,这个时候⼦类调⽤⽗类⾥⾯共同有的⽅法,那么调⽤的顺序是从左到右的顺序。

#从上到下顺序
class Person(object):
   def show(self):
      print('我是⼈类')

class Father(Person):
   def show(self):
      print('我是爸爸')

class Son(Father):
   pass


if __name__ == '__main__':
   son=Son()
   son.show()

⽅法重写

⼦类继承⽗类后,可以调⽤⽗类的⽅法,但是由于⽗类的⽅法⽆法满⾜⼦类的要求后,⼦类可以重写⽗类的⽅法,叫⽅法的重写,如下案例:

class Father(object):
   def show(self):
      print('脾⽓⽕爆')
      
class Son(Father):
   def show(self):
      print('脾⽓温柔')
      
if __name__ == '__main__':
   son=Son()
   son.show()

继承原理

在Python的类继承中,其实存在⼀个⽅法解析MRO的列表,它其实就是所有基类的线性顺序列表,如下所示:

class Person(object):
   def show(self):
      print('我是⼈类')
      
class Father(Person):
   def show(self):
      print('我是爸爸') 
class Son(Father):
   pass
if __name__ == '__main__':
   print(Son.mro())

执⾏后,就会输出类的执⾏顺序了,具体输出的信息如下:

[<class '__main__.Son'>, <class '__main__.Father'>, <class '__main__.Person'>, <class 
'object'>]

所以在Python中,基于MRO的解析顺序规则,就会从左到右开始查找基类,如果找到第⼀个匹配的属性类,就会停⽌查找,如果没有,那就继续查找,直到查找到符合要求的为⽌。MRO其实就是通过⼀个C3线性化算法来实现的,它的核⼼思想为:

⼦类会优先于⽗类检查
多个⽗类会根据它们在列表中的顺序被依次检查
如果对下⼀个类存在两个合法的选择,只能选择第⼀个

深度优先&⼴度优先

Python由于历史的原因,把Python2的类叫经典类,Python3的类叫新式类,其实在Python2中,多个类的继承算法叫深度优先,⽽Python3叫⼴度优先。如下⾯代码:

class A:
   def show(self):
      print('A')
class B(A):
   pass
class C(A):
   def show(self):
      print('C')
class D(B,C):
   pass
if __name__ == '__main__':
   obj=D()
   obj.show()

针对如上的案例代码,调⽤后,调⽤的顺序是不同的,具体如下:
Python3顺序:D--->B--->A--->C
Python2顺序:D--->B--->A

类的内置⽅法

在⼀个类⾥⾯,会存在很多的内置⽅法,今天主要讲解常⽤的内置⽅法,具体如下:

'''
类的内置⽅法:
__init__:类的构造⽅法
__del__:析构⽅法
__str__:返回对象的字符串
__doc__:返回document的信息
__call__:类实例化后的对象(),触发执⾏该内置⽅法执⾏
'''
class Person(object):
   '''把世界上所有的⼈归为⼀类'''
   def __init__(self,name,age):
      self.name=name
      self.age=age
   def __del__(self):
      print('执⾏介绍,资源得到释放')
   def __str__(self):
      return 'my name is {0},and my age is {1}'.format(self.name,self.age)
   def info(self):
      print('欢迎参加⾼级测试开发学习训练营')

   def __call__(self, *args, **kwargs):
      return self.info()
   
if __name__ == '__main__': 
   obj=Person(name='xcj',age=18) 
   print('返回document:',obj.__doc__) 
   print('返回字符串的对象信息:',obj) 
   print('执⾏__call__的⽅法:',obj())

执行后的信息: 

返回document: 把世界上所有的⼈归为⼀类
返回字符串的对象信息: my name is xcj,and my age is 18 
欢迎参加⾼级测试开发学习训练营
执⾏__call__的⽅法: None
执⾏介绍,资源得到释放

类的多态

多态性

多态的优势具体可以总结为如下⼏点,具体为:

  • 增加了持续的灵活性
  • 增加了持续的额外扩展的功能
class Animal(object):
   def talk(self):
      print('动物都是会叫的')
class Cat(Animal):
   def talk(self):
      print('猫也是动物,所以也是会叫的')
def func(animal):
   return animal.talk()
if __name__ == '__main__':
   cat=Cat()
   func(animal=cat)

所以多态性我们也是可以理解为对Cat⽽⾔只是产⽣了⼀个对象,使⽤者完全可以在不需要修改⾃⼰的情况下,就能够调⽤Cat对象的talk的⽅法。针对如上的代码进再次进⾏完善,具体为:

class Animal(object):
   def talk(self):
      print('动物都是会叫的')
class Cat(Animal):
   def talk(self):
      print('猫也是动物,所以也是会叫的')
class Person(Animal):
   def talk(self):
      print('⼈也是动物,所以⼈也是会叫的')
def func(animal):
   return animal.talk()
if __name__ == '__main__':
   person=Person()
   func(animal=person)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜鸟学识

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值