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

Posted aberwang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python之路 -- 面向对象基础2相关的知识,希望对你有一定的参考价值。

面向对象的三大特征

  ——继承,多态,封装

继承

继承是一种创建新类的方式,在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的继承关系

 

 技术分享图片

图一的继承顺序为:
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元

接口类的多继承

技术分享图片
 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.我想保护这个属性,不被子类继承

 













以上是关于python之路 -- 面向对象基础2的主要内容,如果未能解决你的问题,请参考以下文章

Python之路:面向对象(基础)

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

python之路——面向对象(基础篇)

Python之路第七篇--Python基础之面向对象及相关

python学习之路基础篇(第八篇)

学习PYTHON之路, DAY 7 - PYTHON 基础 7 (面向对象基础)