ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Python基础(二十二):面向对象“类”第五课——封装、继承、多态

2021-04-13 23:33:39  阅读:134  来源: 互联网

标签:__ Python 子类 self 多态 第五课 父类 class def


敲黑板,面向对象的三大特征:

封装继承多态

封装

封装性

封装就是隐藏底层的实现细节,只提供公有的接口供外界访问, 这样当底层实现细节改变的时候,就不会对外界造成影响。

私有属性

在类的设计角度,我们可以将属性或方法(类的成员)定义为私有,来实现封装。

私有成员只能在定义类的内部进行访问,在类外是无法进行访问的。

私有成员的定义方式:以_进行开头,但是不能以两个或多个进行结尾。

class Computer:
    def __init__(self,cpu):
        self.cpu = cpu
        # 私有属性(私有的实例属性)
        self.__memory = 1024
        # 在定义私有属性“类的内部”,可以访问私有成员
        #print(self.__memory)
c = Computer("某cpu")
c.__memory  # 可以发现私有属性不能够在外部直接访问

结果如下:

class Computer:
    def __init__(self,cpu):
        self.cpu = cpu
        # 私有属性(私有的实例属性)
        self.__memory = 1024
        # 在定义私有属性“类的内部”,可以访问私有成员
        print(self.__memory)
    def x(self):
        pass
    
    # 如果想要采用公有的方法(在类的外部),访问私有属性。需要额外定义两个方法
    def set_memory(self,memory):
        self.__memory = memory
    def get_memory(self):
        return self.__memory
    
c = Computer("某cpu")
c.get_memory()

结果如下:

为什么非要定义为:私有属性呢?定义为一般的实例属性不是也可以吗?

原因在于:定义为私有属性后。当我们以后需要对类中某属性做出修改时,只需要在内部修改,而不会对外部的使用者,产生影响。

假如不将memory定义为私有属性

class Computer:
	def __init__(self, cpu):
		self.cpu = cpu
		self.memory = 1024


c = Computer("某cpu")
print(c.memory)
# 1024

c.memory = 6666
print(c.memory)
# 6666

假如说,由于某种业务要求,需要将memory改为memory2,那么,我们不仅需要在内部进行修改。同时外部调用者也需要进行修改。假如你有很多粉丝使用这个,估计都会骂你(假如代码中有很多行都需要将memory改为memory2)

其实,私有属性也并非真正的私有。只是将名称进行了一下伪装而已。

伪装成了:类名_私有属性的名称

这就意味着,在类的外部,我们可以通过真实名称对私有属性进行访问。

但是,不建议这么做。伪装就是为了保证封装性,而你非要去捅破。

class Computer:
    def __init__(self,cpu):
        self.cpu = cpu
        self.__memory = 1024
c = Computer("某cpu")
c.__memory  

c._Computer__memory  # 切记不要这么做。这样做破坏了封装性

结果如下:

继承

继承之前

class PythonTeacher:
    def __init__(self,name,group):
        self.name = name
        self.group = group
        
    def introcude(self):
        print(f"我的名字是{self.name},所在小组是{self.group}")
    
    def teach(self):
        print("打开pycharm")
        print("输入代码")
        print("知识点讲解")
        
class JaVaTeacher:
    def __init__(self,name,group):
        self.name = name
        self.group = group
        
    def introcude(self):
        print(f"我的名字是{self.name},所在小组是{self.group}")
        
    def teach(self):
        print("打开eslipse")
        print("输入代码")
        print("知识点讲解")

实现继承

继承体现的是一般与特殊的关系。如果两个类A与B,A(苹果)是一种特殊的B(水果),则我们就称A继承了B,A就是子类,B就是父类。

子类一旦继承了父类,子类就会成为一种特殊的父类,子类就会具备父类的一切特征。因此,父类能够做的事情,子类也可以做到。

子类继承了父类,子类就会继承父类中定义的成员,就好象子类中自己定义了一样。

class Fruit:
    def show(self):
        print("水果")
# 继承,在定义类时,给出继承的父类
class Apple(Fruit):
    pass
f = Fruit()
f.show()

a = Apple()
a.show()

结果如下:

定义类时,若没有显示的继承任何类,则表明继承object类,object是python中最根层次的类。

我们可以将公共的功能提取出来,放入父类中。然后使用每一个子类去继承父类。这样,就无需将这些公共的功能分别放在子类中实现。从而避免了代码的重复性。

子类继承父类,子类可以吸收“父类的功能”,此外,子类还可以增加自己特有的功能。如果父类的功能对于子类来说不适用,子类就可以改造(重写)父类中的功能。

class Bird:
    def fly(self):
        print("鸟飞")
    
    def describe(self):
        print("有羽毛,无牙齿,蛋生")

class Ostrich(Bird):
    # 父类中的fly功能,不适合鸵鸟。因此,子类需要对父类的功能进行修改
    def fly(self):
        print("不会飞")
    
    # 子类增加自己特有的功能
    def run(self):
        print("高速奔跑")

c = Ostrich()
c.fly(),c.describe(),c.run()

结果如下:

成员继承

子类可以继承父类中定义的:类属性、实例属性;类方法、实例方法;静态方法。

class Father:
    class_attr = 1
    
    def __init__(self):
        self.instance_attr = 2 
    
    def instance_method(self):
        pass
    
    @classmethod
    def class_method(cls):
        pass
    
    @staticmethod
    def static_method():
        pass
    
class Son(Father):
    pass

s = Son()

然后子类就可以调用父类的类属性、实例属性;类方法、实例方法;静态方法。

对于父类中的实例属性,我们需要留意。如果子类中定义了自己的init方法,则不会调用父类的init方法。因此,父类方法中绑定的实例属性,就不会绑定到子类对象上,也就是说父类的实力属性,子类不会得到继承。

class Father:
    class_attr = 1
    
    def __init__(self):
        self.instance_attr = 2 
    
    def instance_method(self):
        pass
    
    @classmethod
    def class_method(cls):
        pass
    
    @staticmethod
    def static_method():
        pass
    
class Son(Father):
    def __init__(self):
        pass

so = Son()
so.instance_attr

结果如下:

有时候,父类的初始化,可能"并不完全适合于"子类。这是,子类需要定义自己的init方法。

"并不完全适合于"指的是:父类中,有的实例属性适合雨子类,有的不适合于子类。子类中既要定义自己的init方法,又想使用父类中部分实例属性,那么该怎么做呢?

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

class Student(Person):
     delf __init__(self,name,age,id):
        self.name = name
        self.age = age
        self.id = id
 # 父类的初始化不完全适合于子类,但是,也没有完全不适合于子类   

整改:在子类的init方法中,去调用父类的init方法,这样可以"避免代码重复"。

super()方法登场

class Person():
    def __init__(self,name,age):
        self.name = name
        self.age = age
        
class Student(Person):
     def __init__(self,name,age,id):
        # 调用父类的__init__方法
        super().__init__(name,age)  # 调用父类的__init__方法
        self.id = id

s = Student("梁某人",18,2017011)
s.name,s.age,s.id

结果如下:

私有属性的继承

实际上,私有属性也是可以被子类继承的。只不过,子类继承的不是私有属性本来的名字,而是私有属性伪装后的名字。

虽然子类可以继承并访问父类的私有属性,但是不建议这么做。既然是私有的,肯定是不愿意我们去访问的。

class Father: 
    def __m(self):
        print("私有方法")
    
class Son(Father):
    def p(self):
        # 通过伪装之后的名字,进行访问
        self._Father__m()

s = Son()
s.p()

结果如下:

两个关于继承的内建函数

① isinstance(参数一,参数二)

  • 第一个参数:对象;
  • 第二个参数:类型;
  • 含义:判断第一个指定的参数指定的"对象",是否是第二个参数的指定类型(包括其父类性);
class Father: 
    pass
    
class Son(Father):
    pass

f = Father()
s = Son()

来检测一下:

② issubclass()

  • 第一个参数:类型;
  • 第二个参数:类型;
  • 含义:判断第一个指定的参数类型,是否是第二个参数的指定类型(或者是其子类型);
class Father: 
    pass
    
class Son(Father):
    pass

f = Father()
s = Son()

再来检测一下:

重写

当父类中的成员,对子类不完全适用时,子类就可以重新定义该成员。

class Bird:
    def fly(self):
        print("鸟飞")

class Ostrich(Bird):
    # 父类中的fly功能,不适合鸵鸟。因此,子类需要对父类的功能进行修改
    def fly(self):
        print("不会飞")
    
    # 子类增加自己特有的功能
    def run(self):
        print("高速奔跑")

o = Ostrich()
o.fly()

结果如下:

class Bird:
    def fly(self):
        print("鸟飞")

class Ostrich(Bird):
    # 父类中的fly功能,不适合鸵鸟。因此,子类需要对父类的功能进行修改
    def fly(self):
        # 通过super()方法,可以实现对父类中同名方法的访问
        super().fly()   # super()既可以调用父类中的私有属性。也可以调用父类中的方法
        print("不会飞")

o = Ostrich()
o.fly()

结果如下:

多重继承

python中,一个子类可以继承多个父类。多个父类的成员,都可以被子类所继承。继承多个父类使用 , 分割。

class Rectangle:
    def area(self):
        print("矩形求面积")
        
class Diamond:
    def area(self):
        print("菱形求面积")
        
class Square(Rectangle,Diamond): #总是按照这里的先后顺序,一一继承
    def t(self):
        self.area()

s = Square()
s.t()

结果如下:

class Rectangle:
    def area(self):
        print("矩形求面积")
        
class Diamond:
    def area(self):
        print("菱形求面积")
        
class Square(Diamond,Rectangle): #总是按照这里的先后顺序,一一继承
    def t(self):
        self.area()

s = Square()
s.t()

结果如下:

多继承:按照继承原则,每个父类看作一个分支。按照顺序进行查找,深度优先。但是有一个原则:子类一定会在父类之前被搜索。

class Teacher:
    def __init__(self,name,group):
        self.name = name
        self.group = group
    
    def introcude(self):
        print(f"我的名字是{self.name},所在小组是{self.group}")
      
    def teach(self):
        print("输入代码")
        print("知识点讲解")

class PythonTeacher(Teacher):
    def __init__(self,name,group):
        super().__init__(name,group)
    def teach(self):
        print("打开pycharm")
        super().teach()
        
class JaVaTeacher(Teacher):
    def __init__(self,name,group):
        super().__init__(name,group) 
    def teach(self):
        print("打开eslipse")
        super().teach()

p = PythonTeacher("梁某人", 10)
print(p.introcude(), p.teach())

结果如下:

j = JaVaTeacher("梁三",666)
print(j.group,j.teach())

结果如下:

多态

这个在python中基本体现不出来,知道面向对象有多态这个特性就行了。

标签:__,Python,子类,self,多态,第五课,父类,class,def
来源: https://www.cnblogs.com/pure3417/p/14655836.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有