面向对象的程序设计

--------------------------------------------------------------------------------------------------------------------

·1940年以前:面向机器

  直接使用机器语言(直接编写0和1)编写程序,执行速度快,但是容易写错,难以修改,编写效率底。其后发展出了汇编语言(符号语言)用助记符号替代机器指令的操作码,提升了代码可读性,但仍然是面向机器的语言,编写同样困难。

·脱离机器第一步:面向过程

  面向过程语言:不再关注机器本身的操作指令,储存等方面,而是关注如何一步一步的解决具体的问题,即解决问题的过程。具备可移植性和同用性,更加容易编写和维护。

·结构化程序设计

  大部分面向过程语言中的goto语句导致的面条式代码,极大的限制了程序的规模。结构化程序设计抛弃 goto 语句,采取“自顶向下、逐步细化、模块化”的指导思想。

·面向对象程序设计

  随着硬件和业务的发展,软件的可拓展性和可维护性问题亟待解决。面向对象程序设计开始流行,面向对象的思想更加贴近人类思维的特点。

------------------------------------------------------------------------------------------------------------------------

面向过程的程序设计:

  优点:复杂问题流程化,进而简单化。

  缺点:一套流程解决一个问题,可拓展性差。牵一发动全身。

面向对象的程序设计:

  对象:属性与功能的结合体

  优点:解决程序的拓展性。对一个对象单独修改,立刻反映到整体。

  缺点:

  1.编程复杂度提高。容易出现过度设计的问题。

  2.无法精确的预测问题的处理流程与结果。取决于对象之间的交互。

  面向对象的程序设计并不是全部。对于一个软件质量来说,面向对象的程序设计只是用来解决扩展性。

类:一系列属性与功能相似的对象的结合体。

  现实逻辑中先有对象再有类,但是在程序中务必保证先定义类,后产生对象。

 

class test:     #定义类
    x=1     #定义类的属性
    y=2
    def learn(self,*args,**kwargs):     #定义类的功能
        print(self,args,kwargs)

def ttt():
    print('from ttt')

obj1 = test()        #根据类自定义对象

obj1.x = 123      #对象可以定义自己属性,如与类定义冲突则覆盖
print(obj1.x)
>>>123

obj1.name = ttt           #对象可以定义自己功能,如与类定义冲突则覆盖
print(obj1.name())
>>>from ttt
>>>None

print(obj1.y)   #对象也可以调用类的属性
>>>2

obj1.learn(test.x,1,2,3,a = 6)      #对象可以调用类的功能
>>><__main__.test object at 0x00000000021392E8> (1, 1, 2, 3) {'a': 6}

print(obj1.__dict__)    #__dict__查看对象或类的属性
>>>{'x': 123, 'name': <function ttt at 0x0000000001D42EA0>}
类和对象的定义和关系
class bmw:
    x=1
    y=2
    def __init__(obj,a,b,c):
        obj.name=a
        obj.age=b
        obj.sex=c

obj1=bmw(1,2,3)
print(obj1.age)
__init__ 初始化对象属性
Python中一些类的特殊属性

 

类的两种属性:数据属性和函数属性

1.类的数据属性是所以对象共享的

2 类的函数属性是绑定给对象用的(类中定义的函数都要定义默认写一个参数self绑定对象)

 

面向对象之继承与派生

 

  继承:继承是一种是一种创建新类的方式,新建的类可以继承一个或多个父类(python支持多继承),父类又称为基类或超类,新建的类称为派生类或子类。子类会继承父类的属性,从而解决代码重用的问题

 

一生二 ,二生三,三生万物。

 

继承过程中注意覆盖!

 

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

class father:
    def run(self,x):
        print('%s is father run' % x)
class son(father):
    def run(self,x,y):
        print('%s is son run' % y)
        father.run(self,x)

a = son()
a.run('123','456')
View Code

 

在一个类中以另外一个类的对象作为数据属性,称为类的组合 

 

  抽象类就是从一堆类中抽取相同内容而来的,它是一个特殊类,它的特殊之处在于它只能被继承,不能被实例化。且子类必须实现抽象方法

 

抽象类的实现

 

 

 

 

继承实现的原理  PS:图片引用自linghaifeng博客

  对于自定义的每一个类,Python会计算出一个方法解析顺序(MRO)列表,就是一个简单的所有基类的线性顺序列表可用__mro__查看。Python会从左到右开始查找基类,直到找到第一匹配这个属性的类为止。MRO列表遵循下列三条原则

1,子类会先与父类被检查

2,多个父类会根据他们在列表中的顺序被检查

3,如果对下一个类存在两个合法的选择,选择第一个父类

 

 

 

 

接口:

  java中interface很好的体现了接口的特征;接口是一组功能的集合,而不是一个功能;接口的功能用于交互,所有的对象都是public,即别的对象可操作;接口只定义函数,但不涉及函数的实现;这些功能是相关的。

  基于同一接口实现的类,那么所有这些类在产生对象时,从用法上来说都是一样的,我把它理解为一种‘统一的标准’

 

子类调用父类的方法:

  1,直接用父类的名称加方法名称调用,与普通函数调用类似

  2,super,直接指定父类名,如果没有继承关系,super还是会按照mro继续往后找。  super(类名,self)=func()

多态:一类事物的多种形态

多态性:向不同的对象发送同一信息,不同的对象在接收时会产生不同的行为

 

import abc
class anime(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def talk(self):
        self.talk()

class Cat(anime):
    def talk(self):
        print('miao miao miao')
class Dog(anime):
    def talk(self):
        print('wan wan wan')
class Dark(anime):
    def talk(self):
        print('ga ga ga')
# def talk(anime):
#     anime.talk()
c1=Cat()
d1=Dog()
dark1 = Dark()
# talk(d1)
c1.talk()
View Code

封装:隔离属性,提供接口,隔离复杂度,提高安全性

真正的封装是,经过深入的思考,做出良好的抽象,给出“完整且最小”的接口,并使得内部细节可以对外透明

属性私有化__func(),对外接口 _A__func()

#取款是功能,而这个功能有很多功能组成:插卡、密码认证、输入金额、打印账单、取钱
#对使用者来说,只需要知道取款这个功能即可,其余功能我们都可以隐藏起来,很明显这么做
#隔离了复杂度,同时也提升了安全性

class ATM:
    def __card(self):
        print('插卡')
    def __auth(self):
        print('用户认证')
    def __input(self):
        print('输入取款金额')
    def __print_bill(self):
        print('打印账单')
    def __take_money(self):
        print('取款')

    def withdraw(self):
        self.__card()
        self.__auth()
        self.__input()
        self.__print_bill()
        self.__take_money()

a=ATM()
a.withdraw()

隔离复杂度的例子
View Code

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

python内置方法,遵循了统一访问原则

例子1
class Foo:
    def __init__(self,val):
        self.__NAME=val #将所有的数据属性都隐藏起来

    @property
    def name(self):
        return self.__NAME #obj.name访问的是self.__NAME(这也是真实值的存放位置)

    @name.setter
    def name(self,value):
        if not isinstance(value,str):  #在设定值之前进行类型检查
            raise TypeError('%s must be str' %value)
        self.__NAME=value #通过类型检查后,将值value存放到真实的位置self.__NAME

    @name.deleter
    def name(self):
        raise TypeError('Can not delete')

f=Foo('egon')
print(f.name)
# f.name=10 #抛出异常'TypeError: 10 must be str'
del f.name #抛出异常'TypeError: Can not delete'
View Code
#类的设计者
class Room:
    def __init__(self,name,owner,width,length,high):
        self.name=name
        self.owner=owner
        self.__width=width
        self.__length=length
        self.__high=high
    def tell_area(self): #对外提供的接口,隐藏了内部的实现细节,此时我们想求的是面积
        return self.__width * self.__length


#使用者
>>> r1=Room('卧室','egon',20,20,20)
>>> r1.tell_area() #使用者调用接口tell_area


#类的设计者,轻松的扩展了功能,而类的使用者完全不需要改变自己的代码
class Room:
    def __init__(self,name,owner,width,length,high):
        self.name=name
        self.owner=owner
        self.__width=width
        self.__length=length
        self.__high=high
    def tell_area(self): #对外提供的接口,隐藏内部实现,此时我们想求的是体积,内部逻辑变了,只需求修该下列一行就可以很简答的实现,而且外部调用感知不到,仍然使用该方法,但是功能已经变了
        return self.__width * self.__length * self.__high


#对于仍然在使用tell_area接口的人来说,根本无需改动自己的代码,就可以用上新功能
>>> r1.tell_area()
View Code

 绑定与非绑定

绑定给谁,谁来调用就会把它自身作为第一个参数传入

# classmethod 将类绑定  对象也可以但是传入的值仍然是对象
# staticmethod 解除绑定不论被谁调用都不会自动传值
class Anima:

    @classmethod
    def eat(self):
        print(self)
        pass
    @staticmethod
    def run(self):
        print('from run')
        pass
Anima.eat()
cat = Anima()   #<class '__main__.Anima'>
cat.eat()   #<class '__main__.Anima'>
Anima.run(123)
cat.run(123)
View Code

 

posted @ 2018-10-31 13:45  brzp97  阅读(265)  评论(0)    收藏  举报