面向对象编程思想

- 面向对象是一门编程思想,编程思想仅仅是一门思想,与任何技术无关
- 核心是对象两字,对象能够理解为特征与技能的结合体
- 基于该编程思想编写程序,就比如创造世界,一种造物主的思惟方式
- 优势:可扩张性强
- 缺点:编写程序的复杂难度比面向过程高
以上都是纯理论,理解下用本身的话能编出来就行,下面来讲说核心对象html
在现实世界中,经过一个个的对象,根据相同的特征和行为,再分门别类。python
可是在程序中,必须先有类,再经过调用类,建立对象。编程
那么,我们如何定义类,又如何建立对象呢?(暂时仍是先说理论吧,否则看代码,估计直接懵逼了……)markdown
关于类的致命三问:什么是类?有什么用?怎么使用?函数
-
类的定义:就是类型、类别,跟现实的分类相似。是一系列对象之间相同特征和行为(技能)的结合体post
-
类的做用:我的理解,就是为了建立对象用的。学习
(终于要写代码了,哈哈哈哈哈哈哈)url
- 类的语法:
class 类名: 特征 # 在python 中,用变量来表示特征 行为 # 在python 中,用函数来表示行为,也就是你们所说的技能
如今,咱们来写一我的类,人类的特征有名字,年龄,性别,行为有吃饭,跑步,玩,撸代码了!spa
""" 人类 特征:名字、年龄、性别 行为:吃饭、跑、玩 """ class Person: # 这些都是人的特征 name = "dawn" # 姓名 age = 27 # 年龄 sex = "男" # 性别 # 这些都是人的行为(技能) def eat(self): # 吃饭 print("民以食为天o(∩_∩)o 哈哈") def run(self): # 跑步 print("英雄救美,不存在的!别怂!赶忙跑!!!") def play(self): # 玩 print("大爷!欢迎下次来玩儿啊!") print(Person) print(Person.name) print(Person.play)
输出结果3d
<class '__main__.Person'> # Person 的打印结果 dawn # Person.name 的打印结果 <function Person.play at 0x0000022E54FA7DC8> # Person.play 的打印结果
瞅了这么久,发现了吗?类名,类的行为,类的属性都是咋用的?(理论又来了~~~)
- 类名的命名规范:使用驼峰命名法,即单词的首字母得大写!
- 类提供了一种便捷的获取名字的方式,就是
类名.名字
。类的名字包含特征和行为。我们将类的特征称之为属性,类的行为称之为方法 - 在类的内部定义函数(也就是行为的时候,默认有一个参数
self
),这个是干啥的,等会说
经过输出的内容来看,类名指向的是类的内存地址。如何来查看类的名称空间呢?看代码……
print(Person.__dict__)
输出结果
{'__module__': '__main__', 'name': 'dawn', 'age': 27, 'sex': '男', 'eat': <function Person.eat at 0x00000228C1683558>, 'run': <function Person.run at 0x00000228C1683B88>, 'play': <function Person.play at 0x00000228C1687DC8>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
惊不惊喜!意不意外!对,这就是Person类的名称空间中的内容!!!也就是说类的名称空间是在定义阶段产生
到这里,我们就该聊聊类是如何使用的了。前面咱就说了,类的调用就是对象的建立。说的类的使用就得知道对象是啥了!耐心点,好玩的还在后面!
哈哈哈哈哈!我三连问回来啦!——什么是对象?有什么用?怎么使用?
-
对象的定义:特征与技能的结合体
-
语法:
类名()
我们来瞅瞅对象是如何建立的,类又是如何调用的 !
# 上面咱定义了一个Person类,这里直接拿来用 # 调用Person类后会产生一个对象,使用一个变量接收 p1 = Person() # 输出p1 的属性 print(p1.name, p1.age, p1.sex) # 使用p1 的方法 p1.play() p1.run() p1.eat()
输出结果
dawn 27 男 # p1的属性 大爷!欢迎下次来玩儿啊! # p1.play()的结果 英雄救美,不存在的!别怂!赶忙跑!!! # p1.run()的结果 民以食为天o(∩_∩)o 哈哈 # p1.eat()的结果
刚刚获取了对象的属性(也就是查询),发现没有,这些属性都是类的,咱们可否对对象的属性作个增删改呢?若是修改了对象的属性,类是否随之改变呢?动手试试
修改对象的属性,其实就是对象本身增长了属性
# 修改属性 print(Person.__dict__) # 修改前,Person的名称空间 print(p1.__dict__) # 修改前,p1的名称空间 p1.name = "haha" # 修改对象的name 属性,其实是p1对象本身新增了name 属性 print(Person.__dict__) # 修改后,Person的名称空间 print(p1.__dict__) # 修改后,p1的名称空间
输出结果
增长对象的属性
# 增长属性 print(p1.__dict__) print(Person.__dict__) p1.hobby = "read" print(p1.__dict__) print(Person.__dict__)
输出结果
删除对象的属性
# 删除属性 del p1.sex print(p1.sex) print(Person.__dict__)
输出结果
纵观以上的结果,咱说了那些属性都在类的名称空间里,那么有没有什么方法,让这些属性是经过对象来增删改查的呢?
固然有的啦!那就是__init__()
!咱们来看看使用方式
# 定义一个类 class Person: # 这些都是人的特征 name = "dawn" # 姓名 # __init__() def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex # 这些都是人的行为(技能) def eat(self): # 吃饭 print("民以食为天o(∩_∩)o 哈哈") # 经过类建立两个对象,分别是p1和p2 p1 = Person("haha", 39, "男") p2 = Person("lee", 21, "女") # 查看Person类的名称空间 print(Person.__dict__) # 查看对象p1的名称空间 print(p1.__dict__) # 查看对象p2的名称空间 print(p2.__dict__)
输出结果
发现什么了没有?
__init__()
实现了对象的个性化定制,并且建立对象在传参时,没有传self这个参数。
那是由于__init__()
在调用时,会将对象自己做为第一个参数传入。缘由后期学习之后,才知道。如今就作一个总结好了
- 由对象来调用类的内部函数,称为对象的绑定方法。对象的绑定方法特殊之处在于:会将对象自己看成第一个参数传入方法(咱能够回头看看定义类的时候,是否是每一个行为也就是方法,都有self参数)
__init__()
在调用类时触发,会作如下事情:- 将对象自己看成第一个参数传入方法(缘由:对象的绑定方法)
- 调用时,传入的其余参数一并被
__init__()
接收
接着,咱们来看看,对象是如何对属性作增删改查的
# 获取p1的属性 print(f"姓名:{p1.name},性别:{p1.sex},年龄:{p1.age}") # 修改p1的属性 print(f"修改前,p1的名称空间:{p1.__dict__}") p1.age = 27 print(f"修改后,p1的属性值:{p1.age}") print(f"修改后,p1的名称空间:{p1.__dict__}")
输出结果
再来看看增长(前面就已经举例了,算了仍是再举一个吧)和删除
# 获取p1的属性 print(f"姓名:{p1.name},性别:{p1.sex},年龄:{p1.age}") # 增长属性 print(f"增长hobby前:{p1.__dict__}") p1.hobby = "read" print(f"hobby的取值:{p1.hobby}") print(f"增长hobby后:{p1.__dict__}") # 删除属性 print(f"删除sex前:{p1.__dict__}") del p1.sex print(f"删除sex后:{p1.__dict__}")
输入结果
还有个地方,就是咱刚才一直在说名称空间,那么类的名称空间和对象的名称空间,有什么关系呢?
我们继续看代码
# 经过类建立一个对象 p1 = Person("haha", 39, "男") # 查看Person类的名称空间和属性 print(f"Person的名称空间:{Person.__dict__}") print(f"Person的name属性值:{Person.name}") # 查看对象p1的名称空间和属性 print(f"p1的名称空间:{p1.__dict__}") print(f"p1的name属性值:{p1.name}") # 删除p1的属性name,再打印p1的名称空间和属性 del p1.name print(f"删除name属性后,p1的名称空间:{p1.__dict__}") print(f"删除name属性后,p1的name属性值:{p1.name}")
输出结果
看到没?对象的属性删除后,再去调用这个属性,并无报错,而是将类中的同名属性值获取了过来
那若是类中没有这个属性呢?咱们再来看看
class Person: # 这些都是人的特征 def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex # 经过类建立一个对象 p1 = Person("haha", 39, "男") # 查看对象p1的名称空间和属性 print(f"p1的名称空间:{p1.__dict__}") print(f"p1的name属性值:{p1.name}") # 删除p1的属性name,再打印p1的名称空间和属性 del p1.name print(f"删除name属性后,p1的名称空间:{p1.__dict__}") print(f"删除name属性后,p1的name属性值:{p1.name}")
输出结果
报错了!!!由此咱们能够总结下:
对象先从自身名称空间查找,没有就去类的名称空间查找,再没有就会报错。
对象名字的查找顺序:
对象自身 ----→ 类 ----→ 都没有,报错
定义类及调用的固定模式
class 类名: def __init__(self,参数1,参数2): self.对象的属性1 = 参数1 self.对象的属性2 = 参数2 def 方法名(self):pass def 方法名2(self):pass 对象名 = 类名(1,2) #对象就是实例,表明一个具体的东西 #类名() : 类名+括号就是实例化一个类,至关于调用了__init__方法 #括号里传参数,参数不须要传self,其余与init中的形参一一对应 #结果返回一个对象 对象名.对象的属性1 #查看对象的属性,直接用 对象名.属性名 便可 对象名.方法名() #调用类中的方法,直接用 对象名.方法名() 便可