zoukankan      html  css  js  c++  java
  • (二十)类与对象 ---- 基础知识

    面向对象的设计

    是一种编程模型设计,即把特征(数据属性)与技能(方法属性)整合作为一个结合体,这个结合体即对象,一切皆为对象。

    基于面向对象设计程序就好比在创造一个世界,你就是这个世界的上帝,世间存在的万物皆为对象,不存在的也可以创造出来。

    好比西游记中,如来佛祖要解决的问题是把经书传给东土大唐,如来想了想解决这个问题需要四个人:唐僧,沙和尚,猪八戒,孙悟空,每个人都有各自的特征和技能(这就是对象的概念,特征和技能分别对应对象的数据属性和方法属性),然而这并不好玩,于是如来又安排了一群妖魔鬼怪,为了防止师徒四人在取经路上被搞死,又安排了一群神仙保驾护航,这些都是对象。然后取经开始,师徒四人与妖魔鬼怪神仙交互着直到最后取得真经。如来根本不会管师徒四人按照什么流程去取经(面向过程)。

    注意,这是一种程序设计思想,很多人存在一个误区:只有用class定义类的代码才是面向对象

    def dog (name,type):
        def jiao(dog):
            print('一条叫%s的狗,汪汪汪'%dog['name'])
        def init(name,type):
            dog = {'name':name , 'type':type , 'jiao':jiao}  #name和type是数据属性,jiao是方法属性,三者用一个字典封装,用来初始化实例
            return dog
        return init(name,type)
    
    d1 = dog('小强','二哈')                                #实例化一个对象d1
    print(d1)
    d1['jiao'](d1)
    结果:

    {'name': '小强', 'type': '二哈', 'jiao': <function dog.<locals>.jiao at 0x000001DB61F946A8>}
    一条叫小强的狗,汪汪汪

    这个例子用函数嵌套的的方式,没有用到class,却是一个地地道道的面向对象程序设计,狗的姓名和种类是数据属性,叫是狗的方法属性,这三者作为一个结合体,组成一个'dog类',来实例化一个个对象。

    面向对象的编程

    用定义类+对象(实例)的方式去实现面向对象的设计

    面向对象设计(OOD)不会特别要求面向对象编程语言。事实上,OOD完全可以由纯结构化语言来实现,只不过要想构造具备对象性质和特点的数据类型,就需要在程序上做更多的努力。比如用纯C写的linux kernel其实比c++/java写的大多数项目更加面向对象,linus的泛文件抽象(一切皆文件)恰恰就是面向对象的设计。

    所以面向对象编程和面向对象设计是八竿子打不着两码事,一个是方法论,一个是设计思路

    类与对象

    类即类别、种类,是面向对象设计最重要的概念,对象是特征与技能的结合体,而类则是一系列对象相似的特征与技能的结合体,调用类就可以实例化一个个对象
    那么问题来了,先有的一个个具体存在的对象(比如一个具体存在的人),还是先有的人类这个概念,这个问题需要分两种情况去看
    在现实世界中:先有对象,再有类
    世界上肯定是先出现各种各样的实际存在的物体,然后随着人类文明的发展,人类站在不同的角度总结出了不同的种类,如人类、动物类、植物类等概念
    也就说,对象是具体的存在,而类仅仅只是一个概念,并不真实存在
    在程序中:务必保证先定义类,后产生对象
    这与函数的使用是类似的,先定义函数,后调用函数,类也是一样的,在程序中需要先定义类,后调用类
    不一样的是,调用函数会执行函数体代码返回的是函数体执行的结果return,而调用类会产生对象,返回的是对象

     实例化:

    class student:
        job = '上学'
        def __init__(self,name,age):
            self.name = name
            self.age = age
        def study(self):
            print('%s背着书包上学' %self.name)
    
    p1 = student('小明',18)
    
    print(student.__dict__)        #类的属性列表
    print(p1.__dict__)             #对象的属性列表
    
    print(student.job)             #类的数据属性
    print(p1.job)                  #对象访问类的数据属性
    print(p1.study)                #对象访问类的方法属性
    
    print(p1.name)                 #对象的数据属性
    # print(student.name)          #类访问对象的数据属性,报错
    
    p1.study()
    结果:

    {'__weakref__': <attribute '__weakref__' of 'student' objects>, '__doc__': None, '__dict__': <attribute '__dict__' of 'student' objects>, 'study': <function student.study at 0x000001A60C384620>, '__init__': <function student.__init__ at 0x000001A60C3846A8>, '__module__': '__main__', 'job': '上学'}
    {'name': '小明', 'age': 18}
    上学
    上学
    <bound method student.study of <__main__.student object at 0x000001A60C381DA0>>
    小明
    小明背着书包上学

     

    个人总结:

    类的实例化即产生一个个对象,通过执行类的__init__()方法

    类和对象都有__dict__内置属性,返回一个属性列表;对数据属性和方法属性的所有操作,都可以当做在操作这个__dict__返回的字典

    类有数据属性和方法属性,而严格的讲:对象只有数据属性没有方法属性;如下图类的__init__()方法中,只有对数据属性的定义赋值

    那为什么每个对象都有方法属性,并可以访问类属性?是因为通过寻址引用的方式;所以,一旦类中的方法属性发生变化,对象中的方法属性也马上变化(不论这个对象是否已经被实例化)

    实例化只赋予对象的数据属性,而对象通过寻址引用的方式调用类的方法属性,这样可以节省内存

    对象可以访问类的属性,而类无法访问对象的属性,对象的作用域是先找自己的属性列表(__dict__方法),再找类的属性列表

     类属性的增删改查

    class student:                                 #定义student类
        job = '上学'                                #类的数据属性
        def __init__(self,name,age):
            self.name = name
            self.age = age
        def study(self):                           #类的方法属性
            print('%s背着书包上学' %self.name)
    p1 = student('小明',18)                         #实例化一个对象p1
    
    #
    print(student.job)                             #类名加.的方式访问类属性
    print(p1.job)                                  #对象也可以访问类属性,对象名加.的方式访问类属性
     
    #
    student.country = '中国'                        #新增类的数据属性
    print(p1.country)
    
    def eat_food(self,food):                       #新增类的方法属性
        print('%s正在吃%s' %(self.name,food))
    student.eat = eat_food                         #把eat_food函数的内存地址给student类的eat方法属性,这里eat_food不能加括号,加了括号就是eat_food()执行后的返回值
    p1.eat('米饭')
    
    #
    student.country = '日本'                        #修改类的数据属性
    print(p1.country)
    
    def test(self):                                #修改类的方法属性,但方法属性名还是study
        print('test')
    student.study = test
    p1.study()
    
    #
    del student.job
    print(p1.job)                                  #删除类的数据属性后会报错

     对象属性的增删改查

    class student:
        job = '上学'
        def __init__(self,name,age):
            self.name = name
            self.age = age
        def study(self):
            print('%s背着书包上学' %self.name)
    p1 = student('小明',18)
    
    #
    print(p1.age)                                  #查看对象的数据属性
    print(p1.study)                                #查看对象的方法属性,是寻址引用类的方法属性
    
    #
    p1.female = 'boy'                              #新增对象的数据属性
    print(p1.female)
    
    def test():                                    #新增对象的方法属性,一般不这么用,对象不会独自去定义一个类中没有的方法,没有意义
        print('aaa')
    p1.test = test
    p1.test()
    
    #改                                             #修改对象的数据属性
    p1.age = 20
    print(p1.age)
    
    #
    # del p1.age                                    #删除对象的数据属性
    # print(p1.age)
    结果:

    18
    <bound method student.study of <__main__.student object at 0x00000248CB26A828>>
    boy
    aaa
    20

    几个注意点

    1.通过对象可以访问类的数据属性,但无法修改类的数据属性

    class student:
        job = '上学'
        def __init__(self,name,age):
            self.name = name
            self.age = age
        def study(self):
            print('%s背着书包上学' %self.name)
    p1 = student('小明',18)
    
    p1.job = '上班'         #这样定义其实是新增了一个p1对象的数据属性,与类的数据属性无关。可以这样理解:一个个对象是类实例化出来的,如果通过一个对象就可以改变类的数据属性,那么其他的对象岂不是也变了
    print(p1.job)           #上班
    print(student.job)      #上学

    但是,也有个例:

    class student:
        job = '上学'
        l = ['a','b']
        def __init__(self,name,age):
            self.name = name
            self.age = age
    
        def study(self):
            print('%s背着书包上学' %self.name)
    p1 = student('小明',18)
    
    # p1.l = [1,2,3]                         #通过这种方式不会改变类的数据属性,而是新增了p1对象的数据属性,会在对象的__dict__列表属性中添加,不会在类的__dict__列表属性中添加             
    # print(student.l)
    
    p1.l.append('c')                         #通过这种方式会改变类的数据属性,引用了类的数据属性,恰恰是一个list可变数据类型
    print(student.l)
    结果: ['a', 'b', 'c']

    2.加点的调用方式才是类和对象的属性,不加点的调用方式与类和对象都无关

    school = '初中'                            #全局变量school
    class student:
        job = '上学'
        school = '高中'                        #类的数据属性school
        def __init__(self,name,age):
            self.name = name
            self.age = age
            print(school)                      #初中        不加点的调用方式,这个school既不会去类的属性列表中找,也不会去对象的属性列表中找,所以就是全局变量school
            print(student.school)              #高中        在类的属性列表中找到school这个键值对
        def study(self):
            print('%s背着书包上学' %self.name)
    p1 = student('小明',18)
  • 相关阅读:
    【实践】腾讯云服务器发布项目
    【实践】jdbc批量插入数据
    【转载】jQuery Validate 菜鸟教程
    【转载】jQuery Validate验证框架 + CKEditor 无法验证问题的解决方法
    【实践】获取CKEditor的html文本、纯文本、被选中的内容及赋值
    CKEDITOR的内容js转码,C#控制器解码接收
    jQuery.qrcode生成二维码
    一个表中的两列与另一个表的一列关联的结果显示
    【转载】海明码求解公式规律(转载自计算机网络高分笔记)
    『实践』百度地图同时显示多个路书
  • 原文地址:https://www.cnblogs.com/xulan0922/p/10321649.html
Copyright © 2011-2022 走看看