python面向对象之面向对象编程
引入:编程范式/思想
什么是面向过程
介绍: 核心是“过程”二字,过程就是“流水线”;过程终极奥义是将程序 流程化 优点: 将程序流程化,进而程序的设计会变得简单化 缺点: 可扩展性差
什么是面向对象
介绍: 核心是“对象”二字,对象就是“容器”,用来盛放数据与功能;对象终极奥义是将程序进行高度整合 优点: 提升程序的解耦合程度,进而增强程序的可扩展性 缺点: 设计复杂
一、初识对象
使用对象组织数据。在程序中可以做到和生活中一样,设计表格、生产表格、填写表格的组织形式的。
1.在程序中设计表格:--设计类
class Student: name = None #记录学生姓名
2.在程序中打印生产表格:--创建对象
#基于类创建对象 stu_1 = Student() stu_2 = Student()
3.在程序中填写表格:--对象属性赋值
stu_1.name = "张三" # 为对象赋予name属性 stu_2.name = "张四"
演示类的创建
1.设计一个学生类 :类比生活中设计一张记录学生信息的登记表
class Student: name = None gender = None nationality = None native_place = None age = None
2.创建一个对象(类比生活中打印一张登记表)
stu_1 = Student() stu_2 = Student()
3.对象属性进行赋值(类比生活中:填写表单)
stu_1.name = "张三" stu_1.gender = '男' stu_1.nationality = "中国" stu_1.native_place = "山东省" stu_1.age = "23"
4.获取对象中记录的信息
print(stu_1.name) print(stu_1.gender) print(stu_1.nationality) print(stu_1.native_place) print(stu_1.age)
二、成员方法
1、类的定义和使用语法:
-class是关键字,表示要定义类了 -类的属性,即定义在类中的变量(成员变量) -类的行为,即定义在类中的函数(成员方法) ##语法: class 类名称: 类的属性 类的行为 创建类对象的语法: 对象 = 类名称()
2、成员变量和成员方法的使用:
什么是类的行为(方法)? class Student: name = None # 学生的姓名 age = None # 学生的年龄 def say_hi(self): # 函数是类的方法 print(f'Hello,world!我是{self.name}') stu = Student() stu.name = 'xiao' stu.say_hi() # 输出:Hello,world!我是xiao 可以看出 类中可以: 定义属性用来记录数据 name = None # 学生的姓名 age = None # 学生的年龄 定义函数用来记录行为 def say_hi(self) 其中: 类中定义的属性(变量)称作-- 成员变量 类中定义的行为(函数)称作-- 成员方法 在类中定义成员方法和定义函数基本一致,但仍有细微区别: def 方法名(self,形参1,...,形参N) 方法体 可以看到,在方法定义的参数列表中,有一个:self关键字 self关键字是成员方法定义的时候,必须填写的。 · 它用来表示类对象自身的意思 · 当我们使用类对象调用方法的是,self会自动被python传入 · 在方法内部,想要访问类的成员变量,必须使用self
3、self关键字
self --尽管在参数列表中,但是传参的时候可以忽略它
class Student: name = None def say_hi(self): print('Hello world') def say_hi2(self,msg): print(f'Hello,大家好,{msg}') stu = Student() stu.say_hi() # 调用的时候无需传参 stu.say_hi2('很高兴认识大家') # 调用的时候,需要传msg参数
演示面向对象类中的成员方法定义和使用
# 定义一个带有成员方法的类 class Student: name = None def say_hi(self): print(f"大家好,我是{self.name}") def say_hi2(self,msg): print(f"大家好,我是{self.name},{msg}") stu_1 = Student() stu_1.name = "李四" stu_1.say_hi2("哎哟不错呀") stu_2 = Student() stu_2.name = "李wy" stu_2.say_hi()
三、类和对象
现实世界的事物也有属性和行为,类也有属性和行为; 实用程序中的类,可以完美的描述现实世界的事物。那么为什么要创建对象才能使用呢? 类只是一种程序内的“设计图纸”,需要基于图纸生产实体(对象),才能正常工作 。这种思想就称之为:面向对象编程
使用类和对象描述现实事物
在程序中通过类来描述;
基于类创建对象
这就是面向对象编程: --设计类,基于类创建对象,由对象做具体的工作 。(调用类的过程又称之为实例化)
四、构造方法 (__init__
)
1、属性(成员变量)的赋值
class Student: name = None age = None tel = None student1 = Student() student1.name = 'xiao' student1.age = 18 student1.tel = '13365273678' student2 = Student() student2.name = 'quan' student2.age = 100 student2.tel = '13232324567'
上述代码中,为对象的属性赋值需要依次进行,略显繁琐,有没有更加高效的方式,能够一行代码就能完成呢? 思考:Student()这个括号能否像函数(方法)那样,通过传参的形式对属性赋值呢 答案是可以,需要使用构造方法:__init__()
2、 构造方法:
Python类可以使用__init__()
方法,称之为构造方法
可以实现:--在创建类对象(构造类的时候)
-- 构建类的时候_-init
方法会自动执行
-- 构建类时传入的参数会自动传递给__init__
方法使用
class Student: name = None age = None tel = None #可以省略 def __init__(self,name,age,tel): self.name = name self.age = age self.tel = tel print('Student类创建了一个对象') stu = Student('xiao',18,'12345678945')
3、构造方法注意事项
-- 重要的事情说三遍,构造方法名称:__init__
__init__
__init__
, 千万不要忘记init
前后都有2个下划线
-- 构造方法也是成员方法,不要忘记在参数列表中提供:self
-- 在构造方法内定义成员变量,需要使用self关键字
def __init__(self, name, age,tel): self.name = name # stu1.name = 'xiao' self.age = age # stu1.age = 18 self.tel = tel # stu1.tel = '12345678998' print('Student类创建了一个对象')
这是因为:变量是定义在构造方法内部,如果要成为成员变量,需要用self来表示。
4、构造方法案例
""" 设计一个类,记录学生的: 姓名、年龄、地址,这3类信息 通过for循环,配合input输入语句,并使用构造方法,完成学生信息的键盘录入 输入完成后,使用print语句,完成信息的输出 """ class Student: name = None age = None addres = None # 可以省略 def __init__(self,name,age,addres): self.name = name self.age = age self.addres = addres for x in range(1,10): name_in = input("请输入学生姓名:") age_in = input("请输入学生年龄:") address_in = input("请输入学生地址:") stu = Student(name_in,age_in,address_in) print(f"当前录入第{x}位学生信息,总共需要录入10位学生信息") print(f"学生{x}信息录入完成,信息为:【学生姓名:{stu.name},年龄:{stu.age},地址:{stu.addres}】") print("所有学生的信息录入完毕")
五、面向对象编程
5.1 类的定义与实例化
我们以开发一个清华大学的选课系统为例,来简单介绍基于面向对象的思想如何编写程序
面向对象的基本思路就是把程序中要用到的、相关联的数据与功能整合到对象里,然后再去使用,但程序中要用到的数据以及功能那么多,如何找到相关连的呢?我需要先提取选课系统里的角色:学生、老师、课程等,然后显而易见的是:学生有学生相关的数据于功能,老师有老师相关的数据与功能,我们单以学生为例,
# 学生的数据有 学校 名字 年龄 性别 # 学生的功能有 选课
详细的
# 学生1: 数据: 学校=清华大学 姓名=李建刚 性别=男 年龄=28 功能: 选课 # 学生2: 数据: 学校=清华大学 姓名=王大力 性别=女 年龄=18 功能: 选课 # 学生3: 数据: 学校=清华大学 姓名=牛嗷嗷 性别=男 年龄=38 功能: 选课
我们可以总结出一个学生类,用来存放学生们相同的数据与功能
# 学生类 相同的特征: 学校=清华大学 相同的功能: 选课
基于上述分析的结果,我们接下来需要做的就是在程序中定义出类,然后调用类产生对象
class Student: # 类的命名应该使用“驼峰体” school='清华大学' # 数据 def choose(self): # 功能 print('%s is choosing a course' %self.name)
类体最常见的是变量的定义和函数的定义,但其实类体可以包含任意Python代码,类体的代码在类定义阶段就会执行,因而会产生新的名称空间用来存放类中定义的名字,可以打印Student.__dict__
来查看类这个容器内盛放的东西
print(Student.__dict__) {..., 'school': '清华大学', 'choose': <function Student.choose at 0x1018a2950>, ...}
调用类的过程称为将类实例化,拿到的返回值就是程序中的对象,或称为一个实例
stu1=Student() # 每实例化一次Student类就得到一个学生对象 stu2=Student() stu3=Student()
如此stu1、stu2、stu3全都一样了(只有类中共有的内容,而没有各自独有的数据),想在实例化的过程中就为三位学生定制各自独有的数据:姓名,性别,年龄,需要我们在类内部新增一个__init__
方法,如下
class Student: school='清华大学' #该方法会在对象产生之后自动执行,专门为对象进行初始化操作,可以有任意代码,但一定不能返回非None的值 def __init__(self,name,sex,age): self.name=name # 前面的name是类的属性,后面的name是变量名 self.sex=sex self.age=age def choose(self): print('%s is choosing a course' %self.name)
然后我们重新实例出三位学生
stu1=Student('李建刚','男',28) stu2=Student('王大力','女',18) stu3=Student('牛嗷嗷','男',38)
单拿stu1的产生过程来分析,调用类会先产生一个空对象stu1,然后将stu1连同调用类时括号内的参数一起传给Student.__init__(stu1,’李建刚’,’男’,28)
def __init__(self, name, sex, age): self.name = name # stu1.name = '李建刚' self.sex = sex # stu1.sex = '男' self.age = age # stu1.age = 28
会产生对象的名称空间,同样可以用__dict__查看
print(stu1.__dict__) {'name': '李建刚', 'sex': '男', 'age': 28}
至此,我们造出了三个对象与一个类,对象存放各自独有的数据,类中存放对象们共有的内容
存的目的是为了用,那么如何访问对象或者类中存放的内容呢?
5.2 属性访问
5.2.1 类属性与对象属性
在类中定义的名字,都是类的属性,细说的话,类有两种属性:数据属性和函数属性,可以通过__dict__
访问属性的值,比如Student.__dict__[‘school’]
,但Python提供了专门的属性访问语法
Student.school # 访问数据属性,等同于Student.__dict__['school'] '清华大学' Student.choose # 访问函数属性,等同于Student.__dict__['choose'] <function Student.choose at 0x1018a2950> # 除了查看属性外,我们还可以使用Student.attrib=value(修改或新增属性),用del Student.attrib删除属性。
操作对象的属性也是一样
stu1.name # 查看,等同于obj1.__dict__[‘name'] '李建刚' stu1.course=’python’ # 新增,等同于obj1.__dict__[‘course']='python' stu1.age=38 # 修改,等同于obj1.__dict__[‘age']=38 del obj1.course # 删除,等同于del obj1.__dict__['course']
5.2.2 属性查找顺序与绑定方法
对象的名称空间里只存放着对象独有的属性,而对象们相似的属性是存放于类中的。对象在访问属性时,会优先从对象本身的__dict__
中查找,未找到,则去类的__dict__
中查找
1、类中定义的变量是类的数据属性,是共享给所有对象用的,指向相同的内存地址
# id都一样 print(id(Student.school)) # 4301108704 print(id(stu1.school)) # 4301108704 print(id(stu2.school)) # 4301108704 print(id(stu3.school)) # 4301108704
2、类中定义的函数是类的函数属性,类可以使用,但必须遵循函数的参数规则,有几个参数需要传几个参数
Student.choose(stu1) # 李建刚 is choosing a course Student.choose(stu2) # 王大力 is choosing a course Student.choose(stu3) # 牛嗷嗷 is choosing a course
但其实类中定义的函数主要是给对象使用的,而且是绑定给对象的,虽然所有对象指向的都是相同的功能,但是绑定到不同的对象就是不同的绑定方法,内存地址各不相同
print(id(Student.choose)) # 4335426280 print(id(stu1.choose)) # 4300433608 print(id(stu2.choose)) # 4300433608 print(id(stu3.choose)) # 4300433608
绑定到对象的方法特殊之处在于,绑定给谁就应该由谁来调用,谁来调用,就会将’谁’本身当做第一个参数自动传入(方法__init__
也是一样的道理)
stu1.choose() # 等同于Student.choose(stu1) stu2.choose() # 等同于Student.choose(stu2) stu3.choose() # 等同于Student.choose(stu3)
绑定到不同对象的choose技能,虽然都是选课,但李建刚选的课,不会选给王大力,这正是”绑定“二字的精髓所在。
#注意:绑定到对象方法的这种自动传值的特征,决定了在类中定义的函数都要默认写一个参数self,self可以是任意名字,但命名为self是约定俗成的。
Python中一切皆为对象,且Python3中类与类型是一个概念,因而绑定方法我们早就接触过
#类型list就是类 print(list) <class 'list'> #实例化的到3个对象l1,l2,l3 l1=list([1,2,3]) l2=list(['a','b','c']) l3=list(['x','y']) #三个对象都有绑定方法append,是相同的功能,但内存地址不同 print(l1.append) <built-in method append of list object at 0x10b482b48> print(l2.append) <built-in method append of list object at 0x10b482b88> print(l3.append) <built-in method append of list object at 0x10b482bc8> #操作绑定方法l1.append(4),就是在往l1添加4,绝对不会将4添加到l2或l3 l1.append(4) #等同于list.append(l1,4) print(l1) [1,2,3,4] print(l2) ['a','b','c'] print(l3) ['x','y']
5.3.3 小结
在上述介绍类与对象的使用过程中,我们更多的是站在底层原理的角度去介绍类与对象之间的关联关系,如果只是站在使用的角度,我们无需考虑语法“对象.属性"中”属性“到底源自于哪里,只需要知道是通过对象获取到的就可以了,所以说,对象是一个高度整合的产物,有了对象,我们只需要使用”对象.xxx“的语法就可以得到跟这个对象相关的所有数据与功能,十分方便且解耦合程度极高。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 葡萄城 AI 搜索升级:DeepSeek 加持,客户体验更智能
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏