Day17:面向对象进阶

一、继承相关

  - 继承

    继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,

    父类又可称为基类或超类,新建的类称为派生类或子类。

class Animal:
    def __init__(self,name,food):
        self.name = name
        self.food = food

    def eat(self):
        print('%s 吃 %s'%(self.name,self.food))

class Dog(Animal):
    def swim(self):
        print('%s is swimming'%self.name)

class Bird(Animal):
    def fly(self):
        print('%s is flying'%self.name)


dog = Dog('熊二','狗粮')
dog.eat()

  - 继承、抽象和派生

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

    - 抽象只是分析和设计的过程中的一种技巧,通过抽象可以得到类。

    - 派生:子类可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类),

       需要注意的是,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准了。

    - 在子类中,新建的重名的函数属性,在编辑函数内功能的时候,有可能需要重用父类中重名的那个函数功能,

       应该是用调用普通函数的方式,此时就与调用普通函数无异了,因此即便是self参数也要为其传值。

       在python3中,子类执行父类的方法也可以直接用super方法。

class Person(Animal):
    def __init__(self,name,blood,aggr,money):
        super(Person,self).__init__(name,blood,aggr,)
        self.money = money

    def attack(self,dog):
        dog.blood -= self.aggr

class Dog(Animal):
    def __init__(self,name,blood,aggr,breed):
        super().__init__(name,blood,aggr)
        self.breed = breed

    def bite(self,person):
        person.blood -= self.aggr

person = Person('egon',2000,300,20000)
dog = Dog('alex',2000,200,'金毛')

 

  - 接口类和抽象类

    - 接口类:

      - 继承有两种用途:

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

        二:声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名)

          且并未实现接口的功能,子类继承接口类,并且实现接口中的功能。

      - 借用abc模块来实现接口

from abc import ABCMeta,abstractmethod

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


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

p = Wechatpay() 

      - 归一化:

        接口继承实质上是要求“做出一个良好的抽象,这个抽象规定了一个兼容接口,

        使得外部调用者无需关心具体细节,可一视同仁的处理实现了特定接口的所有对象”——这在程序设计上,叫做归一化。

      - 依赖倒置原则:

        高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该应该依赖细节;

        细节应该依赖抽象。换言之,要针对接口编程,而不是针对实现编程。

  - 抽象类

    - 抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化。

      抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。

      抽象类的本质还是类,指的是一组类的相似性,包括数据属性和函数属性,而接口只强调函数属性的相似性。

  - 多继承问题

    - 在继承抽象类的过程中,我们应该尽量避免多继承;
      而在继承接口的时候,我们反而鼓励你来多继承接口

    - 接口隔离原则:

      使用多个专门的接口,而不使用单一的总接口。即客户端不应该依赖那些不需要的接口。

  - 钻石继承

    - python 的类可以继承多个类,其寻找的方式有两种:深度优先和广度优先。

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

               

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

               

      - 在python3中,所有类默认继承object,但凡是继承了object类的子类,以及该子类的子类,都称为新式类(在python3中所有的类都是新式类)

        没有继承object类的子类成为经典类(在python2中,没有继承object的类,以及它的子类,都是经典类)。

      

      

  - 继承的作用

    减少代码的重用

    提高代码可读性

    规范编程模式

二、多态相关

  - 多态指的是一类事物有多种形态。例如动物有人,狗,猪等多种形态。

  - 多态性:

    多态性是指在不考虑实例类型的情况下使用实例, 多态性使得能够利用同一类(基类)类型的指针来引用不同类的对象,

    以及根据所引用对象的不同,以不同的方式执行相同的操作。

  - 鸭子类型:

    多态可以理解为鸭子类型,是程序设计中的一种风格,“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,

    那么这只鸟就可以被称为鸭子。”在鸭子类型中,关注的不是对象的类型本身,而是它是如何使用的。

三、封装

  隐藏对象的属性和实现细节,仅对外提供公共访问方式。

  - 好处:

    1. 将变化隔离; 

    2. 便于使用;

    3. 提高复用性; 

    4. 提高安全性;

  - 封装原则:

    1. 将不需要对外提供的内容都隐藏起来;

    2. 把属性都隐藏,提供公共方法对其访问。

  - 封装方法:

    封装的方法就是在属性前面加上双下划线,即设置成私有变量或私有方法。

class Teacher:
    def __init__(self,name,pwd):
        self.name = name
        self.__pwd = pwd

    def __pwd(self):
        print(self.__pwd)

egon = Teacher('egon',6666)
print(egon._Teacher__pwd)

    -这种变形需要注意的问题是:    

      1.这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._A__N

      2.变形的过程只在类的内部生效,在定义后的赋值操作,不会变形

   - property属性

    property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值。

import math
class Circle:
    def __init__(self,radius): #圆的半径radius
        self.radius=radius

    @property
    def area(self):
        return math.pi * self.radius**2 #计算面积

    @property
    def perimeter(self):
        return 2*math.pi*self.radius #计算周长

c=Circle(10)
print(c.radius)
print(c.area) #可以向访问数据属性一样去访问area,会触发一个函数的执行,动态计算出一个值
print(c.perimeter)

      - 为什么要用property

        将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,

        这种特性的使用方式遵循了统一访问的原则

  - setter 和 deleter

    

class Goods:

    def __init__(self):
        # 原价
        self.original_price = 100
        # 折扣
        self.discount = 0.8

    @property
    def price(self):
        # 实际价格 = 原价 * 折扣
        new_price = self.original_price * self.discount
        return new_price

    @price.setter
    def price(self, value):
        self.original_price = value

    @price.deleter
    def price(self):
        del self.original_price


obj = Goods()
obj.price         # 获取商品价格
obj.price = 200   # 修改商品原价
print(obj.price)
del obj.price     # 删除商品原价

  - classmethod

    类方法,当这个方法被调用时,我们用类作为第一个参数,而不是那个类的实例,你可以在函数内使用该类和它的属性,而不是特定的实例的属性。

class Classmethod_Demo():
    role = 'dog'

    @classmethod
    def func(cls):
        print(cls.role)

Classmethod_Demo.func()

  - staticmethod

    静态方法,不能将该函数独立的放在类外面,当这个方法被调用的时候,不会把类的实例传递给它,该函数不会依赖对象的属性或者类的属性,也没有必须传的参数

class Staticmethod_Demo():
    role = 'dog'

    @staticmethod
    def func():
        print("当普通方法用")

Staticmethod_Demo.func()

 

posted @ 2017-09-19 19:01  世界辣么大  阅读(49)  评论(0)    收藏  举报