欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

python之路 -- 面向对象基础2

程序员文章站 2022-03-07 16:14:01
面向对象的三大特征 ——继承,多态,封装 继承 继承是一种创建新类的方式,在python中新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类 python中类的继承分为:单继承和多继承 查看继承 提示:如果没有指定基类,python的类会默认继承object类,obje ......

面向对象的三大特征

  ——继承,多态,封装

继承

继承是一种创建新类的方式,在python中新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类

 python中类的继承分为:单继承和多继承

class ParentClass1: #定义父类
    pass

class ParentClass2: #定义父类
    pass

class SubClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是SubClass
    pass

class SubClass2(ParentClass1,ParentClass2): #python支持多继承,用逗号分隔开多个继承的类
    pass

 

 查看继承

>>> SubClass1.__bases__ #__base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类
(<class '__main__.ParentClass1'>,)
>>> SubClass2.__bases__
(<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)

提示:如果没有指定基类,python的类会默认继承object类,object是所有python类的父类

  猫可以:喵喵叫、吃、喝、拉、撒

  狗可以:汪汪叫、吃、喝、拉、撒

如果我们要分别为猫和狗创建一个类,那么就需要为 猫 和 狗 实现他们所有的功能,伪代码如下:
#继承的代码实现
class Animal:

    def eat(self):
        print("%s 吃 " %self.name)

    def drink(self):
        print ("%s 喝 " %self.name)

    def shit(self):
        print ("%s 拉 " %self.name)

    def pee(self):
        print ("%s 撒 " %self.name)


class Cat(Animal):

    def __init__(self, name):
        self.name = name
        self.breed = '猫'

    def cry(self):
        print('喵喵叫')

class Dog(Animal):

    def __init__(self, name):
        self.name = name
        self.breed='狗'

    def cry(self):
        print('汪汪叫')
        
c1 = Cat('小白家的小黑猫')
c1.eat()

#输出结果为:
#小白家的小黑猫 吃 

子类也可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类)
需要注意的是,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准了。(也就是重写父类方法)
所谓重写,就是子类中,有一个和父类相同名字的方法,在子类中的方法会覆盖掉父类中同名的方法

新式类和经典类

# python2.7 新式类和经典类共存,新式类要继承object
# python3中所有类都是新式类,python3中的类默认继承object
    ——新式类继承顺序广度优先
    ——经典类继承顺序深度优先
# 经典类和新式类还有一个区别  mro方法只在新式类中存在

 

继承顺序问题

 1 class F:
 2     def func(self):
 3         print('F')
 4 class A(F):
 5     def func(self):
 6         print('A')
 7 class B(A):pass
 8     # def func(self):
 9     #     print('B')
10 class E(F):
11     def func(self):
12         print('E')
13 class C(E):
14     def func(self):
15         print('C')
16 class D(B,C):
17     pass
18     # def func(self):print('D')
19 
20 d = D()
21 d.func()    #输出的结果为:A
22 print(D.mro())  #打印D的继承关系

 

 python之路 -- 面向对象基础2

图一的继承顺序为:
D->B->A->C->E->F
图二的继承顺序为:
D->B->A->F->C->E

# 只要是子类的对象调用,子类中有的名字 一定用子类的,子类中没有才找父类的,如果父类也没有报错
# 如果父类 子类都有 用子类的
    # 如果还想用父类的,单独调用父类的:
    #       父类名.方法名 需要自己传self参数
    #       super().方法名 不需要自己传self

 super的使用

 1 class Animal:
 2     def __init__(self,name,aggr,hp):
 3         self.name = name
 4         self.aggr = aggr
 5         self.hp = hp
 6     def eat(self):
 7         print('吃药回血')
 8         self.hp+=100
 9 
10 class Dog(Animal):
11     def __init__(self,name,aggr,hp,kind):
12         super().__init__(name,aggr,hp)  #<==>Animal.__init__(self,name,aggr,hp)
13         self.kind = kind       # 派生属性
14     def eat(self):print('dog eating')
15 
16 jin = Dog('狗',200,500,'teddy')
17 print(jin.name)
18 jin.eat()
19 super(Dog,jin).eat()  在外部使用super的时候需要传类和对象

 

super的查找顺序和继承顺序相同
#super 只在python3中存在
 super的本质 :不是单纯找父类 而是根据调用者的节点位置的广度优先顺序来的

 

 1 class A():
 2     def func(self): print('A')
 3 
 4 class B(A):
 5     def func(self):
 6         super().func()
 7         print('B')
 8 
 9 class C(A):
10     def func(self):
11         super().func()
12         print('C')
13 
14 class D(B,C):
15     def func(self):
16         super().func()    
17         print('D')
18 #super的查找顺序和继承顺序相同
19 d = D()
20 d.func()    #输出结果为:A C B D
21 print(D.mro())    #D->B->C->A

 

接口类

python中没有接口类,只是可以实现一个有接口类功能的类9(有抽象类)

继承有两种用途:

一:继承基类的方法,并且做出自己的改变或者扩展(代码重用)

二:声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能

 1 class Alipay:
 2     '''
 3     支付宝支付
 4     '''
 5     def pay(self,money):
 6         print('支付宝支付了%s元'%money)
 7 
 8 class Applepay:
 9     '''
10     apple pay支付
11     '''
12     def pay(self,money):
13         print('apple pay支付了%s元'%money)
14 
15 
16 def pay(payment,money):
17     '''
18     支付函数,总体负责支付
19     对应支付的对象和要支付的金额
20     '''
21     payment.pay(money)
22 
23 
24 p = Alipay()
25 pay(p,200)    #支付宝支付了200元

接口类的多继承

python之路 -- 面向对象基础2
 1 #接口类的多继承
 2 #tiger 走路 游泳
 3 #swan 走路 游泳 飞
 4 #oldying 走路 飞
 5 from abc import abstractmethod,ABCMeta    #1.引用这个模块
 6 class Swim_Animal(metaclass=ABCMeta):     #2.传入这个metaclass=ABCMeta
 7     @abstractmethod                       #3.加上此装饰器的语法糖@abstractmethod
 8     def swim(self):pass                   #满足这3点的就可以成为接口类
 9 
10 class Walk_Animal(metaclass=ABCMeta):
11     @abstractmethod
12     def walk(self):pass
13 
14 class Fly_Animal(metaclass=ABCMeta):
15     @abstractmethod
16     def fly(self):pass
17 
18 class Tiger(Walk_Animal,Swim_Animal):
19     def walk(self):
20         pass
21     def swim(self):
22         pass
23 
24 class OldYing(Fly_Animal,Walk_Animal):pass
25 class Swan(Swim_Animal,Walk_Animal,Fly_Animal):pass
接口类的多继承

 

 1 from abc import ABCMeta,abstractmethod
 2 
 3 class Payment(metaclass=ABCMeta):
 4     @abstractmethod
 5     def pay(money):
 6         print("支付了%s" % money)
 7 
 8 class Wechatpay(Payment):
 9     def fuqian(money):
10         print('微信支付了%s元'%money)
11 
12 # p = Wechatpay(200) #此处实例化会报错
13 #只实例化一个类,不调用类中的方法就会报错
14 
15 p = Wechatpay.fuqian(200)
16 p2 = Wechatpay.pay(100)
17 p3 = Payment.pay(50)
18 #执行结果:
19 #微信支付了200元
20 #支付了100
21 #支付了50

 

 抽象类

与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化
抽象类与普通类的不同之处在于:抽象类中有抽象方法,该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接口有点类似,但其实是不同的,
python支持抽象类,多继承

多态

多态指的是一类事物有多种形态

 1 import abc
 2 class File(metaclass=abc.ABCMeta): #同一类事物:文件
 3     @abc.abstractmethod
 4     def click(self):
 5         pass
 6 
 7 class Text(File): #文件的形态之一:文本文件
 8     def click(self):
 9         print('open file')
10 
11 class ExeFile(File): #文件的形态之二:可执行文件
12     def click(self):
13         print('execute file')
14 
15 多态动态绑定(在继承的背景下使用时,有时也称为多态性)
16 多态性是指在不考虑实例类型的情况下使用实例

鸭子类型
所谓鸭子类型,定义是‘是动态类型的一种风格‘。一个对象的特征不是由父类决定,而是通过对象的方法决定的。

封装

在python中用双下划线开头的方式将属性或者隐藏起来(设置成私有的)

 1 class Person:
 2     __key = 123  # 私有静态属性
 3     def __init__(self,name,passwd):
 4         self.name = name
 5         self.__passwd = passwd   # 私有属性
 6 
 7     def __get_pwd(self):         # 私有方法
 8         return self.__passwd   #只要在类的内部使用私有属性,就会自动的带上_类名
 9 
10     def login(self):          # 正常的方法调用私有的方法
11         self.__get_pwd()
12 
13 alex = Person('alex','alex3714')
14 print(alex._Person__passwd)   # _类名__属性名(在内的外部只能通过这种方式调用私有属性和方法)
15 print(alex.get_pwd())        #此处的调用方法会报错

 会用到私有的这个概念的场景

1.隐藏起一个属性 不想让类的外部调用

2.我想保护这个属性,不想让属性随意被改变

3.我想保护这个属性,不被子类继承