python 面向对象

发布时间:2018-03-18 19:08:02编辑:admin阅读(4950)

    面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想。OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。


    面向过程的程序设计把计算机程序视为一系列的命令集合,即一组函数的顺序执行。为了简化程序设计,面向过程把函数继续切分为子函数,即把大块函数通过切割成小块函数来降低系统的复杂度。


    而面向对象的程序设计把计算机程序视为一组对象的集合,而每个对象都可以接收其他对象发过来的消息,并处理这些消息,计算机程序的执行就是一系列消息在各个对象之间传递。


    我们一般认为, 如果你只是写一些简单的脚本,去做一些一次性任务,用面向过程的方式是极好的,但如果你要处理的任务是复杂的,且需要不断迭代和维护 的, 那还是用面向对象最方便了。


    世界万物,皆可分类,皆为对象。

    只要是对象,就肯定属于某种品类,有属性。


    在Python中,所有数据类型都可以视为对象,当然也可以自定义对象。自定义的对象数据类型就是面向对象中的类(Class)的概念。


    OOP编程是利用“类”和“对象”来创建各种模型来实现对真实世界的描述,使用面向对象编程的原因一方面是因为它可以使程序的维护和扩展变得更简单,并且可以大大提高程序开发效率 ,另外,基于面向对象的程序可以使它人更加容易理解你的代码逻辑,从而使团队开发变得更从容。


    面向对象的几个核心特性如下


    Class 类

    一个类即是对一类拥有相同属性的对象的抽象、蓝图、原型。在类中定义了这些对象的都具备的属性(variables(data))、共同的方法


    Object 对象 

    一个对象即是一个类的实例化后实例,一个类必须经过实例化后方可在程序中调用,一个类可以实例化多个对象,每个对象亦可以有不同的属性,就像人类是指所有人,每个人是指具体的对象,人与人之前有共性,亦有不同


    Encapsulation 封装

    在类中对数据的赋值、内部调用对外部用户是透明的,这使类变成了一个胶囊或容器,里面包含着类的数据和方法


    Inheritance 继承

    一个类可以派生出子类,在这个父类里定义的属性、方法自动被子类继承


    Polymorphism 多态

    多态是面向对象的重要特性,简单点说:“一个接口,多种实现”,指一个基类中派生出了不同的子类,且每个子类在继承了同样的方法名的同时又对父类的方法做了不同的实现,这就是同一种事物表现出的多种形态。

    编程其实就是一个将具体世界进行抽象化的过程,多态就是抽象化的一种体现,把一系列具体事物的共同点抽象出来, 再通过这个抽象的事物, 与不同的具体事物进行对话。

    对不同类的对象发出相同的消息将会有不同的行为。


    面向对象编程(Object-Oriented Programming )介绍

    对于编程语言的初学者来讲,OOP不是一个很容易理解的编程方式。虽然知道OPP的特性,

    但是一到真正写程序的时候,还是很多人喜欢用函数式编程来写代码。


    无论用什么形式来编程,我们都要明确记住以下原则:

    写重复代码是非常不好的低级行为

    你写的代码需要经常变更 


    虽然函数可以解决代码重复问题,但是OPP比函数,在代码修改和扩展变化方面更容易

    比如CS游戏

    class Role(object):
        def __init__(self, name, role, weapon, life_value=100, money=15000):
            #玩家角色名
            self.name = name
            #角色
            self.role = role
            #武器
            self.weapon = weapon
            #生命值
            self.life_value = life_value
            #金币
            self.money = money
    
        #开枪
        def shot(self):
            print("shooting...")
        #中枪
        def got_shot(self):
            print("ah...,I got shot...")
        #买装备
        def buy_gun(self, gun_name):
            print("%s just bought %s" % (self.name,gun_name))
    
    #生成一个角色
    r1 = Role('Jack', 'police', 'AK47')
    #执行动作
    r1.shot()
    r1.got_shot()
    r1.buy_gun('AK47')

    执行输出:

    shooting...

    ah...,I got shot...

    just bought AK47


    在真正开始分解上面代码含义之之前,我们现来了解一些类的基本定义

    类的语法

    class Dog(object):
        print("hello,I am a dog!")
    
    d = Dog()  # 实例化这个类,
    # 此时的d就是类Dog的实例化对象
    
    # 实例化,其实就是以Dog类为模版,在内存里开辟一块空间,存上数据,赋值成一个变量名

    上面的代码其实有问题,想给狗起名字传不进去。

    class Dog(object):
        def __init__(self, name, dog_type):
            self.name = name
            self.type = dog_type
    
        def sayhi(self):
            print("hello,I am a dog, my name is ", self.name)
    
    d = Dog('LiChuang', "京巴")
    d.sayhi()

    为什么有__init__? 为什么有self? 此时的你一脸蒙逼,相信不画个图,你的智商是理解不了的!  


    画图之前, 你先注释掉这两句

    # d = Dog('LiChuang', "京巴")
    # d.sayhi()
    
    print(Dog)

    没实例直接打印Dog输出如下

    class '__main__.Dog'


    这代表什么?代表 即使不实例化,这个Dog类本身也是已经存在内存里的对不对, yes, cool,那实例化时,会产生什么化学反应呢?

    720333-20161118182241279-1433722961.png

    根据上图我们得知,其实self,就是实例本身!你实例化时python会自动把这个实例本身通过self参数传进去

    你说好吧,假装懂了, 但下面这段代码你又不明白了, 为何sayhi(self),要写个self呢?

    class Dog(object):
        ...
    
        def sayhi(self):
            print("hello,I am a dog, my name is ", self.name)

    这个原因,下面会讲到

    好了,明白 了类的基本定义,接下来我们一起分解一下上面的代码分别 是什么意思

    class Role(object): #定义一个类, class是定义类的语法,Role是类名,(object)是新式类的写法,必须这样写,以后再讲为什么
        def __init__(self,name,role,weapon,life_value=100,money=15000): #初始化函数,在生成一个角色时要初始化的一些属性就填写在这里
            self.name = name #__init__中的第一个参数self,和这里的self都 是什么意思? 看下面解释
            self.role = role
            ...

    上面的这个__init__()叫做初始化方法(或构造方法), 在类被调用时,这个方法(虽然它是函数形式,但在类中就不叫函数了,叫方法)会自动执行,进行一些初始化的动作,所以我们这里写的__init__(self,name,role,weapon,life_value=100,money=15000)就是要在创建一个角色时给它设置这些属性,那么这第一个参数self是干毛用的呢? 

     

    初始化一个角色,就需要调用这个类一次: 

    r1 = Role('Alex','police','AK47') #生成一个角色 , 会自动把参数传给Role下面的__init__(...)方法
    r2 = Role('Jack','terrorist','B22')  #生成一个角色

    我们看到,上面的创建角色时,我们并没有给__init__传值,程序也没未报错,是因为,类在调用它自己的__init__(…)时自己帮你给self参数赋值了, 

    r1 = Role('Alex','police','AK47') #此时self 相当于 r1 ,  Role(r1,'Alex','police','AK47')
    r2 = Role('Jack','terrorist','B22')#此时self 相当于 r2, Role(r2,'Jack','terrorist','B22')

    为什么这样子?你拉着我说你有些犹豫,怎么会这样子?

    你执行r1 = Role('Alex','police','AK47’)时,python的解释器其实干了两件事:

    在内存中开辟一块空间指向r1这个变量名

    调用Role这个类并执行其中的__init__(…)方法,相当于Role.__init__(r1,'Alex','police',’AK47’),这么做是为什么呢? 是为了把'Alex','police',’AK47’这3个值跟刚开辟的r1关联起来,是为了把'Alex','police',’AK47’这3个值跟刚开辟的r1关联起来,是为了把'Alex','police',’AK47’这3个值跟刚开辟的r1关联起来,重要的事情说3次, 因为关联起来后,你就可以直接r1.name, r1.weapon 这样来调用啦。所以,为实现这种关联,在调用__init__方法时,就必须把r1这个变量也传进去,否则__init__不知道要把那3个参数跟谁关联呀。

    明白了么哥?所以这个__init__(…)方法里的,self.name = name , self.role = role 等等的意思就是要把这几个值 存到r1的内存空间里。

    如果还不明白的话,哥,去测试一下智商吧, 应该不会超过70,哈哈。

    为了暴露自己的智商,此时你假装懂了,但又问, __init__(…)我懂了,但后面的那几个函数,噢 不对,后面那几个方法 为什么也还需要self参数么? 不是在初始化角色的时候 ,就已经把角色的属性跟r1绑定好了么? 

    good question, 先来看一下上面类中的一个buy_gun的方法: 

    def buy_gun(self, gun_name):
        print("%s just bought %s" % (self.name,gun_name))

    上面这个方法通过类调用的话要写成如下: 

    r1 = Role('Alex','police','AK47')
    r1.buy_gun('B21') #python 会自动帮你转成 Role.buy_gun(r1,'B21')

    执行结果

    #Alex has just bought B21 

    依然没给self传值 ,但Python还是会自动的帮你把r1 赋值给self这个参数, 为什么呢? 因为,你在buy_gun(..)方法中可能要访问r1的一些其它属性呀, 比如这里就访问 了r1的名字,怎么访问呢?你得告诉这个方法呀,于是就把r1传给了这个self参数,然后在buy_gun里调用 self.name 就相当于调用r1.name 啦,如果还想知道r1的生命值 有多少,直接写成self.life_value就可以了。 说白了就是在调用类中的一个方法时,你得告诉人家你是谁。

     

    好啦, 总结一下2点:

    1.上面的这个r1 = Role('Alex','police','AK47’)动作,叫做类的“实例化”, 就是把一个虚拟的抽象的类,通过这个动作,变成了一个具体的对象了, 这个对象就叫做实例

    2.刚才定义的这个类体现了面向对象的第一个基本特性,封装,其实就是使用构造方法将内容封装到某个具体对象中,然后通过对象直接或者self间接获取被封装的内容

     


关键字

上一篇: python re模块

下一篇: python 面向对象之变量