• 面向对象编程


    面向对象编程

    一、对象的概念

    面向对象是一门编程思想

    ​ 核心是“对象”二字

    对象指的是“特征与技能”的结合体

    • 优点
      • 可扩展性高
    • 缺点
      • 编写程序的复杂程度比面向过程高

    所有的程序都是由“数据”与“功能”组成,因而编写程序的本质就是定义出一系类的数据,然后定义出一系列的功能来对数据进行操作。在学习“对象”之前,程序中的数据与功能是分离开的

    # 数据name、age、sex
    name = 'tank'
    age = 18
    sex = 'female'
    
    # 功能:tell_info
    def tell_info(name, age, sex):
        print(f'<{name}:{age}:{sex}>')
    
    # 此时若想执行查看个人信息的功能,需要同时拿来两样东西,一类是功能tell_info,另外一类则是多个数据name、age、sex,才能执行,非常麻烦
    tell_info(name, age, sex)
    

    二、 类与对象

    类就是类别/种类,是面向对象分析和设计的基石

    如果说对象是用来存放数据与功能的容器,那么类则是用来存放多个对象相同的数据与功能的容器

    从两种角度去看待

    • 现实世界中
      • 现有一个个的对象,经过社会的文明发展,随之总结出类(人类)
    • 在程序中
      • 必须要先有类,再通过“调用类,产生对象”

    强调:在程序中,必须要事先定义类,然后再调用类产生对象(调用类拿到的返回值就是对象)

    产生对象的类与对象之间存在关联,这种关联指的是:对象可以访问到类中共有的数据与功能,所以类中的内容仍然是属于对象的,类只不过是一种节省空间、减少代码冗余的机制,面向对象编程最终的核心仍然是取使用对象

    • 如何定义类(如何写类并产生对象)
      • 先从现实世界中通过一个个对象总结出类
      • 然后再定义类,后调用类产生对象

    三、面向对象编程

    3.1 类的定义与实例化

    我们以开发一个清华大学的选课系统为例,来介绍基于面向对象的思想如何编写程序

    面向对象的基本思路就是把程序中要用到的、相关联的数据与功能整合到对象里,然后再去使用,但程序中要用到的数据以及功能那么多,我们需要先提取选课系统里的角色:学生、老师、课程等,然后显而易见的是:学生有学生先关的数据与功能,老师有老师相关的数据与功能

    # 学生的数据有
    学校
    名字
    年龄
    性别
    # 学生的功能有
    选课
    

    详细的

    # 学生1
    	数据:
        	学校 = 清华大学
            姓名 = 苟汪汪
            性别 = 女
            年龄 = 28
        功能:
        	选课
    # 学生2
    	数据:
        	学校 = 清华大学
            姓名 = 毛喵喵
            性别 = 女
            年龄 = 25
        功能:
        	选课
    # 学生3
    	数据:
        	学校 = 清华大学
            姓名 = 牛莽莽
            性别 = 男
            年龄 = 30
    	功能:
        	选课
    

    我们可以总结出一个学生类,用来存放学生们相同的数据与功能

    # 学生类
    	相同的特征:
        	学校 = 清华大学
        相同的功能:
        	选课
    

    基于上述的分析,我们接下来要做的就是在程序中定义出类,然后调用类产生对象

    class Student:  # 类的命名应该使用“驼峰体”
        school = '清华大学'  # 数据
    
        def choose(self):  # 功能
            print('%s is choosing a course' % self.name)
    

    类体最常见的就是变量的定义和函数的定义,但其实类体可以包含任意Python代码,类体的代码在类定义阶段就会执行,因为会产生新的名称空间来存放类中定义的名字,可以打印Student.__dict__来查看类这个容器内盛放的东西

    print(Student.__dict__)
    {'__module__': '__main__', 'school': '清华大学', 'choose': <function Student.choose at 0x0000017AE8879A60>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None}
    

    调用类的过程称为将类实例化,拿到的返回值就是程序中的对象,或称为一个实例

    stu1 = Student()	#每实例化一次就得到一个学生对象
    print(stu1)
    stu2 = Student()
    print(stu2)
    stu3 = Student()
    print(stu3)
    
    <__main__.Student object at 0x0000026C62037BA8>
    <__main__.Student object at 0x0000026C6203F198>
    <__main__.Student object at 0x0000026C6203F358>
    

    如此stu1、 stu2、 stu3全都一样了(只有类中有的内容,而没有各自独有的数据),想在实例化的过程中就位三位学生定制各自独有的数据:姓名,性别,年龄,需要我们在类内部新增一个__init__方法

    class Student:
        school = '清华大学'
    
        # 该方法会在对象产生之后自动执行,专门为对象进行初始化操作,可以有任意代码,但一定不能返回非None的值
        def __init__(self, name, sex, age):
            self.name = name
            self.sex = sex
            self.age = age
    
        def choose(self):
            print('%s is choosing a course' % self.name)
    

    然后我们重新实例出三位学生

    stu1 = Student('苟汪汪', '女', 28)
    stu2 = Student('毛喵喵', '女', 25)
    stu3 = Student('牛莽莽', '男', 30)
    

    单拿stu1的产生过程来分析,调用类会先产生一个空对象stu1,然后将stu1连同调用类时括号内参数一起传给Student.__init__(stu1,'苟汪汪','女',28)

    def __init__(self, name, sex, age):
        self.name = name	# = '苟汪汪'
        self.sex = sex		# = '女'
        self.age = age		# = 28
    

    会产生对象的名称空间,同样可以用__dict__查看

    print(stu1.__dict__)
    {'name': '苟汪汪', 'sex': '女', 'age': 28}
    
    3.2 属性访问

    3.2.1 类属性与对象属性

    在类中定义的名字,都是类的属性,细说的话,类有两种属性:数据属性和函数属性,可以通过__dict__访问属性的值,比如Student.__dict__['school']

    print(Student.school) # 访问数据属性,等同于Student.__dict__['school']
    print(Student.choose) # 访问函数属性,等同于Student.__dict__['choose']
    
    清华大学
    <function Student.choose at 0x00000207292599D8>
    

    操作对象的属性也是一样的

    print(stu1.name) # 查看,等同于obj1.__dict__['name']
    '苟汪汪'
    stu1.course = 'python' # 新增,等同于obj1.__dict__['course'] = 'python'
    stu1.age = 38 # 修改,等同于obj1.__dict__['age'] = 38
    del stu1.course  # 删除,等同于del obj1.__dict__['course']
    

    3.2.2 属性查找顺序与绑定方法

    对象的名称空间里只存放着对象独有的属性,而对象们相似的属性是存放于类中的。对象在访问属性时,会优先从对象本身的__dict__中查看,未找到,则取类中的__dict__中查找

    1、类中定义的变量是类的数据属性,是共享给所有对象用的,指向相同的内存地址

    print(id(Student.school))	#1450119990160
    
    print(id(stu1.school))	#1450119990160
    print(id(stu2.school))	#1450119990160
    print(id(stu3.school))	#1450119990160
    # id 都一样
    

    2、 类中定义的函数时类的函数属性,类可以使用,但必须遵循函数的参数规则,有几个参数需要传几个参数

    print(Student.choose(stu1)) #苟汪汪 is choosing a course
    print(Student.choose(stu2))	#毛喵喵 is choosing a course
    print(Student.choose(stu3))	#牛莽莽 is choosing a course
    

    但其实类中定义的函数主要是给对象使用的,而且是绑定给对象的,虽然所有对象指向的都是相同的功能,但是绑定到不同的对象就是不同的绑定方法,内存地址各不相同

    print(id(Student.choose)) # 1748242242008
    
    print(id(stu1.choose))	# 1748211873224
    print(id(stu2.choose))	# 1748211873224
    print(id(stu3.choose))	# 1748211873224
    

    绑定到对象的方法特殊之处在于,绑定给谁就应该由谁来调用,谁来调用,就会将谁本身当做第一个参数自动传入(方法__init__也是一样的道理)

    stu1.choose() # 等同于Student.choose(stu1)
    stu2.choose() # 等同于Student.choose(stu2)
    stu3.choose() # 等同于Student.choose(stu3)
    

    绑定到不同对象的choose技能,虽然都是选课,但苟汪汪选的课,不会选给毛喵喵,这正是“绑定”的精髓

    print(list)
    <class 'list'>
    
    # 三个对象都有绑定方法append,是相同的功能,但内存地址不同
    print(id(l1.append))
    print(id(l2.append))
    print(id(l3.append))
    
    # 操作绑定方法l1.append(4),就是往l1添加4,绝对不会将4添加到l2或l3
    l1.append(4)
    print(l1)	# [1, 2, 3, 4]
    print(l2)	# ['a', 'b', 'c']
    print(l3)	# ['x', 'y']
    
  • 相关阅读:
    php如何导出csv文件(代码示例)
    【转】Linux 进程终止后自动重启
    【转】小程序web-view覆盖原生组件
    搭建 LNMP 环境
    数据库索引的底层原理
    NoSQL 介绍
    MySQL Explain详解
    centos搭建 SVN 服务器
    【转】提高mysql千万级大数据SQL查询优化30条经验(Mysql索引优化注意)
    优化mysql slave的同步速度
  • 原文地址:https://www.cnblogs.com/YGZICO/p/11959690.html
Copyright © 2020-2023  润新知