疫情环境下的网络学习笔记 python 4.7

4.7

今日正课

面向对象编程

  • 一种编程思想,与面向对象一样相当于武功不同的流派,没有高低之分,各自有应用场景
  • 面向过程,核心是“过程”,过程是流水线,是用来解决问题的步骤,核心思想是将程序流程化
  • 面向对象,核心是对象

对象

  • 对象是“容器”,是用来盛数据和功能的,可以看作数据和功能的集合体
  • 对象的奥义就是将程序“整合”

举例

需求1:选课系统

# 程序中应该有学生的数据,课程的信息,以及操作的功能
# 学生信息
stu_name = 'deimos'
stu_age = 18
stu_sex = 'male'

# 学生功能,例:打印学生的信息
def show_info():
    print('名字:%s 年龄:%s 性别:%s'%(stu_name,stu_age,stu_sex))
    
# 学生功能,改学生信息
def set_info():
    global stu_name,stu_sex,stu_age
    stu_name =x
    stu_sex = y
    stu_age = z
    
# 课程数据
course_name = 'python'
course_period = '6mons'
course_score = 10

# 课程的功能,例:打印课程信息
def show_course():
    print(course_name,course_period,course_score)
    

像这样,数据和功能分开,我们发现有一些功能只会操作一部分数据,如课程功能只操作课程的数据,但是所有的数据和功能都放在一起,混乱。所以希望把每种功能和数据分别进行整合

# 学生的容器 = 学生的数据 + 学生的功能
# 课程的容器 = 课程的数据 + 课程的功能

整合后,不同类型的功能和数据分割开,解开耦合

需求2:化妆

  • 要化妆,需要准备好原材料和工具

    • 原材料:眼影,粉底
    • 工具:眼线笔,粉扑
  • 类似地,原材料和工具对应编程中的数据和功能。如果不同作用的工具和原材料放在一起,很乱,比如椒盐和眼影放在一起,锅铲和眼线笔放在一起。所以把做菜的工具和材料,与化妆的材料和工具,分别整合后分开装到容器里,要化妆的时候使用化妆的容器,做菜的时候使用做菜的容器

  • 我们之前学的模块,把不同用处的功能和数据分开成多个文件,其实就是用面向对象的思想编程,模块就是一个对象。但是用文件整合功能单位比较大,希望有一种别的方式

  • 字典中可以放数据,函数名,一个字典当作一个容器,里面放相关功能和数据,也是一种方法,但是字典里的函数还是要在字典之外定义,不能把函数体代码放进字典,还是不够精简,达不到真正整合的需求

    在使用方法的时候,直接把字典传给这个方法,让方法去字典中找需要的数据和功能

python中有语法允许我们将数据和功能很好地整合到一起

类介绍

  • 两个具有相同属性的对象,其中有不一样的数据,也有一样的数据。使用多个具有相同属性的对象,不需要存多个同样的数据:使用“类”
  • 类也是容器,该容器用来存放同类对象共有的数据和功能
  • 必须要事先定义类,然后再调用类产生对象(调用类拿到的返回值就是对象)。产生对象的类与对象之间存在关联,这种关联指的是:对象可以访问到类中共有的数据与功能,所以类中的内容仍然是属于对象的,类只不过是一种节省空间、减少代码冗余的机制,面向对象编程最终的核心仍然是去使用对象

面向对象的语法

先定义类,再调用类产生对象

类语法

定义类

  • 定义方式:class 类名:

  • 类最常用的是定义数据和功能,但其实可以包含任何其他代码

  • 类体代码在定义阶段就会运行,会产生类的名称空间,名称空间中放类中的各种名字

    # 命名类,使用驼峰体
    class Student:
        # 变量的定义
        stu_school = 'boy'
        # 功能的定义,传入一个对象,可以使用对象中的数据,对象可以是外部传入的
        def show_info(stu_obj):
            pass
        print('=====')
    
  • 使用 类名.__dict__ 可以以字典形式查看类中的所有名字

    通过类名.__dict__[名字] 操作字典的方式得到类字典中的名字和功能

  • python提供的语法,使用点 . 去访问类

    # 访问数据属性
    print(Sudent.school_name)
    # 访问函数属性
    print(Sudent.show_info)
    

调用类

调用类产生对象,将类实例化,拿到的返回值就是程序中的对象

stu1_obj = Student()
print(stu_obj.__dict__)
# {}
  • 调用类不是执行类体代码,而是制造一个关联,此时对象中只有类中公有的数据和功能,没有独立的数据和功能,使用 __dict__ 看到的是空字典

  • 可以操作字典或使用点,为对象添加独有的功能和数据,添加后__dict__ 看到的是独有的内容

    class Students:
        school = 'new east'
        def cook(obj):
            print(f'My name is {obj.name}, my schol is {Students.school}')
    
    deimos = Students()
    deimos.name = 'deimos'
    print(deimos.__dict__)
    
    #{'name': 'deimos'}
    

出现问题

创建多个对象,多个对象需要添加多种同类的数据,比如每个学生对象,添加他们的年龄和名字,名字各不相同,但是纪录名字的变量名都是 student_name,student_age,为每个学生的每个名字和年龄都操作字典麻烦,需要改进

改进一:使用函数初始化

sut1_obj = Student()
sut2_obj = Student()
# 创建空对象
def init(obj1,x,y,z):
    # 为空对象传入独有的属性
	obj.stu_name = x
	obj.stu_age = y
	obj.stu_sex = z
    
init(stu1_obj,'deimos',21,'male')
init(stu2_obj,'aaa',21,'male')

改进二:调用类产生对象的时候自动调用init产生独有属性的功能,把init放到类里面去,前后加上下划线

  • 只要在类中定义__init__()方法,python会在调用类的时候自动触发执行
  • 其中__init__ 会自动将调用类时产生的空对象作为第一个参数传进来,于是我们只需要传init中的其他参数

于是,对于改进一,把__init__西写在类中,调用的时候传入init需要的其他参数

class Students:
    school = 'New east'
    def __init__(obj,name,age):
        obj.name = name
        obj.age = age
    def cook(obj):
        print(f'My name is {obj.name}, my schol is {Students.school}, my age is {obj.age}')

deimos = Students('deimos',18)
# 在生成对象的时候就传入独有的参数
deimos.cook()
aaa = Students('aaa',20)
aaa.cook()

# My name is deimos, my schol is New east, my age is 18
# My name is aaa, my schol is New east, my age is 20

调用类的过程

调用类的过程又称为实例化,发生了三件事

  1. 先产生一个空对象
  2. python会自动调用类中的 __init__ 方法,将空对象以及调用类时括号内传入的参数一并传给 __init__
  3. 返回初始化完的对象

**总结__init__ 方法 **

  1. 会在调用类时自动触发执行,用来为对象初始化自己独有的数据
  2. init 内应该存放的是为对象初始化属性的功能,但是也可以放其他任意代码,例如想要在调用类的时候就立刻执行的代码
  3. init 默认返回None,也必须返回none

属性查找问题

查找对象中的数据,先从对象本身找,找不到则去类中找。查找类中的数据,访问到的是变量值,查找函数,找到的是函数的内存地址

数据属性

其实类中的东西都是给对象用的,同一类下共享的数据属性,在不同对象下访问的地址都一样

  • 类中本身的值一变,所有都对象的这个值都一起变
  • 本身不是类的值,而是通过init传进的独有的值,通过一个对象改变,则只能改变当前对象的

例:计算实例化的次数

# 每次实例化,都运行了一次__init__
class atudent:
    count = 0
    def __init__(obj):
        atudent.count += 1
    # 改变Student的值,而不是obj的值

deimos = atudent()
print(deimos.count)

函数属性

类的函数属性是给对象用的,虽然所有对象指向的都是相同的功能,但是绑定到不同的对象就是不同的绑定方法,内存地址各不相同

Student.show_info(stu1_obj)
# 可以这样写,相当于使用一个普通函数,stu1作为参数传入,相当于普通函数
# <function ...>
stu1_obj.show_info()
# 使用student1对象所在类下的公共方法,会被python识别为绑定方法,与普通函数不一样
# <bound ...>

绑定方法的特殊之处在于,谁来绑定方法就会将谁作为第一个参数自动传入。所以在类中定义的函数,一定要有一个参数 obj,用来接收绑定时候传进来的对象。如果定义的时候没有这个参数,相当于有实参没形参,会报错

在类里面定义函数,一定要有一个参数,约定设为self,用于接收自动传入的对象

class Student:
	def show_info(self):
		pass

之前在学点方法的时候,遇到self,当它不存在,因为self是自动传进来的参数,被谁点绑定就是作用于谁,如list.append(item),相当于list.append(self,item)

总结

对于扩展性高的部分,可以使用面向对象,对于其他普通部分不一定要使用类对象

猜你喜欢

转载自www.cnblogs.com/telecasterfanclub/p/12654911.html
4.7