一、什么是对象?
1、面向过程编程
自我们第一次接触编程,就开始学习面向过程编程,面向过程的重点是“过程”。我们在写一个程序时,都会思考,先实现什么,再实现什么,最后实现什么,举个简单的例子:要实现计算1+1,我们要先给程序传入两个值1和1,然后调用程序计算1+1并赋值给变量,最后打印结果,这就是面向过程编程。面向过程编程可以看做是程序的基石。
2、面向对象编程
什么又是面向对象编程呢?面向对象编程的核心是“对象”。
# 原始方法,按照粉底——腮红——眼妆的顺序,逐个给到数据和定义方法 x = "粉底" def 美妆蛋(): print("开始上底妆") y = "腮红" def 化妆刷(): print("开始打腮红") x = "眼影" def 眼影刷(): print("开始画眼妆") # 面向对象 def 美妆蛋(): print("开始上底妆") def 化妆刷(): print("开始打腮红") def 眼影刷(): print("开始画眼妆") # 这里定义的化妆包字典就是一个对象,包含了化妆这个程序的数据与功能 化妆包 = { "化妆品": ["粉底", "腮红", "眼影"], "化妆工具": [美妆蛋, 化妆刷, 眼影刷] }
二、类与对象
1、什么是类?
通过上诉的例子,我们知道我们有多个方法可以创建对象:列表、字典、集合等,但是我们可以发现使用这些“工具”创建的对象有很多局限,首先是取用还是不太清晰,使用时需要通过key索引取值,其次,我们还需要实现定义方法,查看相应功能不够便利。于是python为广大程序员提供了一种便捷的建立对象的方法,这就需要用到类,使用关键字class创建类,语法如下:
class 类名: # 定义变量 x = 1 ... # 定义函数,其中的self参数是代表自动传入对象,后续会讲解,这里可以忽略 def f1(self): pass def f2(self): pass ...
类的本质可以看做是一个存放数据与功能的字典,但是在类里面可以定义变量,可以定义函数,这无疑提升了代码体的“整合”程度。
# 定义一个类:化妆包 class 化妆包: x = "粉底" y = "腮红" x = "眼影" def 美妆蛋(): print("开始上底妆") def 化妆刷(): print("开始打腮红") def 眼影刷(): print("开始画眼妆") print(化妆包.__dict__) # 可以得到一个字典,里面包含了所有的功能与方法 # {'__weakref__': <attribute '__weakref__' of '化妆包' objects>, '化妆刷': <function 化妆包.化妆刷 at 0x01976E40>, '__module__': '__main__', 'x': '眼影', '__doc__': None, '眼影刷': <function 化妆包.眼影刷 at 0x01976ED0>, '美妆蛋': <function 化妆包.美妆蛋 at 0x01976D68>, '__dict__': <attribute '__dict__' of '化妆包' objects>, 'y': '腮红'}
因为类的实质就是一个字典,我们可以通过:类名.dict[“变量名”]方法调用字典中的方法,以上为了演示效果,才使用了中文作为变量名、函数名和类名,这样不可取,希望大家不要模仿,后续将会按照规范为大家演示
# 定义一个学生类 class Student: school = "北京大学" name = "zhangdada" # 打印学生信息 def show_info(): print("学生信息") # 通过字典调用变量 print(Student.__dict__["school"]) print(Student.__dict__["name"]) # 通过字典调用函数 Student.show_info()
每次都要使用__dict__方法未免有点繁琐,于是python也提供了一个简洁的调用方法(真为懒人考虑):类.属性;没错只需要一个.就可以解决,后面的属性就是我们在类中定义的变量或者函数
# 调用高级用法 class Student: school = "北京大学" name = "zhangdada" # 打印学生信息 def show_info(): print("学生信息") # 通过.调用变量 print(Student.school) print(Student.name) # 通过.调用函数 Student.show_info()
讲到这里,可能有的小伙伴已经开始晕了,啥是类?啥是对象?一个程序会有很多对象,但是某一类对象可能存在一些共有的数据或者功能,我们每创建一个对象就要写一遍这些共有的相同代码,就会使得代码冗余,那为什么不把这些共同的数据与功能放在一起,那么每次创建对象时,只需要拿来共有的数据与功能,加上自己的特性数据与功能,一个对象就诞生了,并且没有冗余代码。
我们上面说到,类实质就是一个字典,存放共有数据与功能的字典,通过类可以生成一系列相似但是又有自己特性的对象。例如有一个类是动物,存有长毛,是动物的共有特性,那么加上“汪汪汪”叫就是对象狗,加上“喵喵喵”叫就是对象猫。
2、类的定义与调用
类的定义我们上面易筋经介绍了,需要补充的是,类中定义的方法都叫做属性,类的属性分为变量属性和函数属性,顾名思义,代表了类中定义的变量和函数,其实类中可以有任何类型的代码,但是我们常用的就是这两个属性,可以通过上述的__dict__方法查看类中的全部属性
如何使用类创造对象呢?
# 类的调用 class Student: school = "北京大学" name = "zhangdada" # 打印学生信息 def show_info(): print("学生信息") # 生成对象 stu1 = Student() stu2 = Student()
可以看到,stu1、stu2就是通过调用产生的对象,这个对象可以访问到类中的所有数据与方法,面向对象编程操作的就是这个对象,但是我们发现一个问题,这样创建的对象好像是一样的,我们打印一下两个对象对应的字典
# 生成对象 stu1 = Student() stu2 = Student() print(stu1.__dict__) print(stu2.__dict__) #结果 {} {}
果然是一样的但是我们之前说过,对象是共有部分加自有特性,这就需要用到__init__属性
# 类的调用 class Student: school = "北京大学" name = "zhangdada" # 初始化对象,赋予对象自有的特性 def __init__(self,name,age,gender): self.name = name # stu1.__dict__["name"] = name self.age = age # stu1.__dict__["age"] = age self.gender = gender # stu1.__dict__["gender"] = gender # 打印学生信息 def show_info(): print("学生信息") # 生成对象 stu1 = Student("zhangdada",18,"male")
init__属性其实就是在为对象设置初始化的特性数据,上述事例中,以stu1为例,展示了在类中加入__init(self,name,age,gender)方法后,只需要调用对象时传入参数name、age、gender,生成了包含name、age、gender的对象stu1,使用相同方法,可以产生更多对象。
在调用类生成对象时,发生了三件事:
下图反映了对象与类之间的关系
对象查找属性的顺序:现在类自己的__dict__中寻找——>然后去类__dict__中寻找
类的属性查找
# 类的调用 class Student: school = "北京大学" name = "zhangdada" # 初始化对象,赋予对象自有的特性 def __init__(self,name,age,gender): self.name = name # stu1.__dict__["name"] = name self.age = age # stu1.__dict__["age"] = age self.gender = gender # stu1.__dict__["gender"] = gender # 打印学生信息 def show_info(): print("学生信息") # 生成对象 stu1 = Student("zhangdada",18,"male") stu2 = Student("hhh",20,"female") # 调用数据属性 print(id(Student.school)) # 29441344 print(id(stu1.school)) # 29441344 print(id(stu2.school)) # 29441344
# 类的调用 class Student: school = "北京大学" name = "zhangdada" # 初始化对象,赋予对象自有的特性 def __init__(self,name,age,gender): self.name = name # stu1.__dict__["name"] = name self.age = age # stu1.__dict__["age"] = age self.gender = gender # stu1.__dict__["gender"] = gender # 打印学生信息 def show_info(self): print("%s" % self.name) # 生成对象 stu1 = Student("zhangdada",18,"male") stu2 = Student("hhh",20,"female") # 通过类名调用数据属性 Student.show_info(stu1) # zhangdada
# 类的调用 class Student: school = "北京大学" name = "zhangdada" # 初始化对象,赋予对象自有的特性 def __init__(self,name,age,gender): self.name = name # stu1.__dict__["name"] = name self.age = age # stu1.__dict__["age"] = age self.gender = gender # stu1.__dict__["gender"] = gender # 打印学生信息 def show_info(self): print("%s" % self.name) # 生成对象 stu1 = Student("zhangdada",18,"male") stu2 = Student("hhh",20,"female") # 通过类名调用数据属性 Student.show_info(stu1) # zhangdada # 绑定方法 stu1.show_info() # 等同于Student.show_info(stu1) stu2.show_info() # 等同于Student.show_info(stu2) # 返回结果为: # zhangdada # hhh
绑定方法与非绑定方法详解
类中定义的函数分为两大类
1:绑定方法:绑定给谁就应该由谁来调用,谁来调用就会将自己当作第一个参数自动传入
绑定给对象
绑定给类
2:非绑定方法:不与任何人绑定,意味着谁都可以来调用,但是无论谁来调用就是一个普通函数,没有自动传参的效果
绑定给对象
# 绑定给对象 class Mysql: def __init__(self,iq,sport): self.iq = iq self.sport = sport def info(self): print("%s %s" % (self.iq,self.sport)) user1 = Mysql("1.2.3.2",6625) user1.info()
绑定给类
ID = "208.1.1.1" Port = 3340 # 绑定给类, class Mysql: def __init__(self,iq,sport): self.iq = iq self.sport = sport def info(self): print("%s %s" % (self.iq,self.sport)) @classmethod # 表示将类自己作为第一个参数传入函数,在类中快速生成对象 def from_conf(cls): return cls(ID,Port) obj = Mysql.from_conf() obj.info() # 208.1.1.1 3340
非绑定方法
ID = "208.1.1.1" Port = 3340 # 绑定给类, class Mysql: def __init__(self,iq,sport): self.id = self.create_id() self.iq = iq self.sport = sport def info(self): print("%s %s" % (self.iq,self.sport)) @classmethod def from_conf(cls): return cls(ID,Port) @staticmethod # 不会再讲对象当做第一个参数传入属性,此时可以看走一个函数 def create_id(): import uuid return uuid.uuid4()