wns9778.com_威尼斯wns.9778官网

热门关键词: wns9778.com,威尼斯wns.9778官网
wns9778.com > 计算机教程 > python之路 -- 面向对象基础2wns9778.com

原标题:python之路 -- 面向对象基础2wns9778.com

浏览次数:121 时间:2019-05-10

面向对象的三大特征

一、继承

  ——继承,多态,封装

1,什么是继承

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

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

class ParentClass1: #定义父类
    pass

class ParentClass2: #定义父类
    pass

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

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

 pass

2,查看继承

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

提示:如果没有指定基类,python的类会默认继承object类,object是所有python类的基类,它提供了一些常见方法(如__str__)的实现。

>>> ParentClass1.__bases__
(<class 'object'>,)
>>> ParentClass2.__bases__
(<class 'object'>,)

 3,继承与抽象(先抽象再继承)

抽象即抽取类似或者说比较像的部分。

抽象分成两个层次: 

1.将奥巴马和梅西这俩对象比较像的部分抽取成类; 

2.将人,猪,狗这三个类比较像的部分抽取成父类。

继承:是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构。

4,继承与重用性

wns9778.com 1wns9778.com 2

==========================第一部分
例如

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

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

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


#猫和狗有大量相同的内容
class 猫:

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

    def 吃(self):
        # do something

    def 喝(self):
        # do something

    def 拉(self):
        # do something

    def 撒(self):
        # do something

class 狗:

    def 汪汪叫(self):
        print '汪汪叫'

    def 吃(self):
        # do something

    def 喝(self):
        # do something

    def 拉(self):
        # do something

    def 撒(self):
        # do something



==========================第二部分
上述代码不难看出,吃、喝、拉、撒是猫和狗都具有的功能,而我们却分别的猫和狗的类中编写了两次。如果使用 继承 的思想,如下实现:

  动物:吃、喝、拉、撒

     猫:喵喵叫(猫继承动物的功能)

     狗:汪汪叫(狗继承动物的功能)

伪代码如下:
class 动物:

    def 吃(self):
        # do something

    def 喝(self):
        # do something

    def 拉(self):
        # do something

    def 撒(self):
        # do something

# 在类后面括号中写入另外一个类名,表示当前类继承另外一个类
class 猫(动物):

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

# 在类后面括号中写入另外一个类名,表示当前类继承另外一个类
class 狗(动物):

    def 汪汪叫(self):
        print '汪汪叫'




==========================第三部分
#继承的代码实现
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()

c2 = Cat('小黑的小白猫')
c2.drink()

d1 = Dog('胖子家的小瘦狗')
d1.eat()

使用继承来重用代码比较好的例子

使用继承来解决代码重用的例子

继承与重用性

在开发程序的过程中,如果我们定义了一个类A,然后又想新建立另外一个类B,但是类B的大部分内容与类A的相同时

我们不可能从头开始写一个类B,这就用到了类的继承的概念。

通过继承的方式新建类B,让B继承A,B会‘遗传’A的所有属性(数据属性和函数属性),实现代码重用

class Animal:
    '''
    人和狗都是动物,所以创造一个Animal基类
    '''
    def __init__(self, name, aggressivity, life_value):
        self.name = name  # 人和狗都有自己的昵称;
        self.aggressivity = aggressivity  # 人和狗都有自己的攻击力;
        self.life_value = life_value  # 人和狗都有自己的生命值;

    def eat(self):
        print('%s is eating'%self.name)

class Dog(Animal):
    pass

class Person(Animal):
    pass

egg = Person('egon',10,1000)
ha2 = Dog('二愣子',50,1000)
egg.eat()
ha2.eat()

5,派生

当然子类也可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类),需要注意的是,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准了。

class Animal:
    '''
    人和狗都是动物,所以创造一个Animal基类
    '''
    def __init__(self, name, aggressivity, life_value):
        self.name = name  # 人和狗都有自己的昵称;
        self.aggressivity = aggressivity  # 人和狗都有自己的攻击力;
        self.life_value = life_value  # 人和狗都有自己的生命值;

    def eat(self):
        print('%s is eating'%self.name)

class Dog(Animal):
    '''
    狗类,继承Animal类
    '''
    def bite(self, people):
        '''
        派生:狗有咬人的技能
        :param people:  
        '''
        people.life_value -= self.aggressivity

class Person(Animal):
    '''
    人类,继承Animal
    '''
    def attack(self, dog):
        '''
        派生:人有攻击的技能
        :param dog: 
        '''
        dog.life_value -= self.aggressivity

egg = Person('egon',10,1000)
ha2 = Dog('二愣子',50,1000)
print(ha2.life_value)
print(egg.attack(ha2))
print(ha2.life_value)

在子类中,新建的重名的函数属性,在编辑函数内功能的时候,有可能需要重用父类中重名的那个函数功能,应该是用调用普通函数的方式,即:类名.func(),此时就与调用普通函数无异了,因此即便是self参数也要为其传值.

6,super

class A:
    def hahaha(self):
        print('A')

class B(A):
    def hahaha(self):
        super().hahaha()
        #super(B,self).hahaha()
        #A.hahaha(self)
        print('B')

a = A()
b = B()
b.hahaha()
super(B,b).hahaha()

class A:
    def hahaha(self):
        print('A')

class B(A):
    def hahaha(self):
        super().hahaha()
        #super(B,self).hahaha()
        #A.hahaha(self)
        print('B')

a = A()
b = B()
b.hahaha()
super(B,b).hahaha()

帮你了解super

通过继承建立了派生类与基类之间的关系,它是一种'是'的关系,比如白马是马,人是动物。

当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如教授是老师

>>> class Teacher:
...     def __init__(self,name,gender):
...         self.name=name
...         self.gender=gender
...     def teach(self):
...         print('teaching')
... 
>>> 
>>> class Professor(Teacher):
...     pass
... 
>>> p1=Professor('egon','male')
>>> p1.teach()
teaching

7,钻石继承

继承

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

 

 wns9778.com 3

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

接口类的多继承

wns9778.com 4wns9778.com 5

 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支持抽象类,多继承

继承顺序

wns9778.com 6

当类是经典类时,多继承情况下,会按照深度优先方式查找

当类是新式类时,多继承情况下,会按照广度优先方式查找

经典类和新式类:

从写法上类或者父类继承了object类,那么该类便是新式类,否则便是经典类。

wns9778.com 7

wns9778.com 8wns9778.com 9

class A(object):
    def test(self):
        print('from A')

class B(A):
    def test(self):
        print('from B')

class C(A):
    def test(self):
        print('from C')

class D(B):
    def test(self):
        print('from D')

class E(C):
    def test(self):
        print('from E')

class F(D,E):
    # def test(self):
    #     print('from F')
    pass
f1=F()
f1.test()
print(F.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性

#新式类继承顺序:F->D->B->E->C->A
#经典类继承顺序:F->D->B->A->E->C
#python3中统一都是新式类
#pyhon2中才分新式类与经典类

继承顺序

8,继承原理

 python到底是如何实现继承的,对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列

>>> F.mro() #等同于F.__mro__
[<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

 

 为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。
而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:
1.子类会先于父类被检查
2.多个父类会根据它们在列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类

多态

 二、多态

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

 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 多态性是指在不考虑实例类型的情况下使用实例

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

1,抽象类与接口类

封装

在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.我想保护这个属性,不被子类继承

 

接口类

继承有两种用途:

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

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

class Alipay:
    '''
    支付宝支付
    '''
    def pay(self,money):
        print('支付宝支付了%s元'%money)

class Applepay:
    '''
    apple pay支付
    '''
    def pay(self,money):
        print('apple pay支付了%s元'%money)


def pay(payment,money):
    '''
    支付函数,总体负责支付
    对应支付的对象和要支付的金额
    '''
    payment.pay(money)


p = Alipay()
pay(p,200)

class Alipay:
    '''
    支付宝支付
    '''
    def pay(self,money):
        print('支付宝支付了%s元'%money)

class Applepay:
    '''
    apple pay支付
    '''
    def pay(self,money):
        print('apple pay支付了%s元'%money)

class Wechatpay:
    def fuqian(self,money):
        '''
        实现了pay的功能,但是名字不一样
        '''
        print('微信支付了%s元'%money)

def pay(payment,money):
    '''
    支付函数,总体负责支付
    对应支付的对象和要支付的金额
    '''
    payment.pay(money)


p = Wechatpay()
pay(p,200)   #执行会报错

借用abc模块来实现接口

from abc import ABCMeta,abstractmethod

class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self,money):
        pass


class Wechatpay(Payment):
    def fuqian(self,money):
        print('微信支付了%s元'%money)

p = Wechatpay() #不调就报错了

实践中,继承的第一种含义意义并不很大,甚至常常是有害的。因为它使得子类与基类出现强耦合。

继承的第二种含义非常重要。它又叫“接口继承”。
接口继承实质上是要求“做出一个良好的抽象,这个抽象规定了一个兼容接口,使得外部调用者无需关心具体细节,可一视同仁的处理实现了特定接口的所有对象”——这在程序设计上,叫做归一化。

归一化使得高层的外部使用者可以不加区分的处理所有接口兼容的对象集合——就好象linux的泛文件概念一样,所有东西都可以当文件处理,不必关心它是内存、磁盘、网络还是屏幕(当然,对底层设计者,当然也可以区分出“字符设备”和“块设备”,然后做出针对性的设计:细致到什么程度,视需求而定)。

本文由wns9778.com发布于计算机教程,转载请注明出处:python之路 -- 面向对象基础2wns9778.com

关键词: wns9778.com

上一篇:《DOM编程艺术》五、动态创建标记

下一篇:没有了