一、什么是类和对象
类,可以看成种类,类型,从一组对象中提取到的相似部分。所有的对象都属于一个类,称为类的实例。数据类型就是类。
对象(object)基本上可以看做数据(特性)以及由一系列可以存取、操作这些数据的方法所组成的集合。
1 2 | print(int) print(Garen) |
---|
输出结果:
1 2 | <class 'int'> <class '__main__.Garen'> |
---|
二、类
1、初始类
1 声明类 (和声明函数很相似)
1 2 3 4 | 类的定义格式 class 类名: '类的文档字符串' 类体 |
---|
2、创建一个类
1 2 | class Data: pass |
---|
*Python编程中习惯类名使用单数单词并且首字母大写
类是数据与函数的结合,二者称为类的属性
1 2 3 4 | class Garen: #定义英雄盖伦的类,不同的玩家可以用它实例出自己英雄; camp='Demacia' #所有玩家的英雄(盖伦)的阵营都是Demacia; def attack(self,enemy): #普通攻击技能,enemy是敌人; enemy.life_value-=self.aggressivity #根据自己的攻击力,攻击敌人就减掉敌人的生命值。 |
---|
3、类的作用
3.1、属性引用(类名.属性)
(1)引用类的数据属性(类名.变量名)
1 | print(Garen.camp) # 引用类的数据属性,该属性与所有对象/实例共享 |
---|
输出结果为:
1 | Demacia |
---|
(2)引用类的函数属性(类名.函数名)
1 | print(Garen.attack) #引用类的函数属性,该属性也共享 |
---|
输出结果为:
1 | <function Garen.attack at 0x00000059CE8FAF28> |
---|
(3)类的属性操作
1 2 | Garen.name='Garen1' #增加属性 print(Garen.name) #查询属性 |
---|
输出结果为:
1 | Garen1 |
---|
1 2 3 | del Garen.name #删除属性 print(Garen.name) |
---|
输出结果为:
1 | AttributeError: type object 'Garen' has no attribute 'name' #报错 |
---|
1 2 | Garen.camp="aaaa" #修改属性 print(Garen.camp) |
---|
输出结果为:
1 | aaaa |
---|
3.2、查看类的属性
dir(类名):查出的是一个名字列表
类名.__dict__:查出的是一个字典,key为属性名,value为属性值
3.3、特殊的类属性
类名.__name__# 类的名字(字符串)
类名.__doc__# 类的文档字符串
类名.__base__# 类的第一个父类(在讲继承时会讲)
类名.__bases__# 类所有父类构成的元组(在讲继承时会讲)
类名.__dict__# 类的字典属性
类名.__module__# 类定义所在的模块
类名.__class__# 实例对应的类(仅新式类中)
3.4、实例化
(1)__init__实例化
类名加括号就是实例化,会自动触发__init__函数的运行,可以用他来为每个实例定制自己的特性
1 2 3 4 5 6 7 8 | class Garen: camp='Demacia' def __init__(self,nickname,aggressivity=58,life_value=455): self.nickname=nickname #为自己的盖伦起个别名; self.aggressivity=aggressivity #英雄都有自己的攻击力; self.life_value=life_value #英雄都有自己的生命值; def attack(self,enemy): print("attack %s" % enemy) |
---|
实例化:类名 括号
1 | g1=Garen('草丛伦') |
---|
#就是在执行Garen.__int__(g1,’草丛伦’),然后执行__init__内的代码g1.nickname=’草丛伦’等
(2)self作用
self的作用是在实例化时自动将对象/实例本身传给__init__的第一个参数,self可以是任意名字,但是self是大家公认的。
4、抽象类
如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。
从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。
从实现角度来看,抽象类与普通类的不同之处在于:抽象类中只能有抽象方法(没有实现功能),该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接口有点类似,但其实是不同的,即将揭晓答案
4.1、在python中实现实现抽象类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | #一切皆文件 import abc #利用abc模块实现抽象类 class All_file(metaclass=abc.ABCMeta): all_type='file' @abc.abstractmethod #定义抽象方法,无需实现功能 def read(self): '子类必须定义读功能' pass @abc.abstractmethod #定义抽象方法,无需实现功能 def write(self): '子类必须定义写功能' pass # class Txt(All_file): # pass # # t1=Txt() #报错,子类没有定义抽象方法 class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法 def read(self): print('文本数据的读取方法') def write(self): print('文本数据的读取方法') class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法 def read(self): print('硬盘数据的读取方法') def write(self): print('硬盘数据的读取方法') class Process(All_file): #子类继承抽象类,但是必须定义read和write方法 def read(self): print('进程数据的读取方法') def write(self): print('进程数据的读取方法') wenbenwenjian=Txt() yingpanwenjian=Sata() jinchengwenjian=Process() #这样大家都是被归一化了,也就是一切皆文件的思想 wenbenwenjian.read() yingpanwenjian.write() jinchengwenjian.read() print(wenbenwenjian.all_type) print(yingpanwenjian.all_type) print(jinchengwenjian.all_type) |
---|
5、抽象类与接口
抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计 。
6、类名称空间
创建一个类就会创建一个类的名称空间,用来存储类中定义的所有名字,这些名字称为类的属性
而类的良好总属性:数据属性和函数属性
其中类的数据属性是共享给所有对象
1 2 | print(id(g1.camp)) #引用的地址是一样的 print(id(Garen.camp)) |
---|
输出结果为:
1 2 | 364617767096 364617767096 |
---|
其中类的函数属性是绑定到所有对象
1 2 | print(id(g1.attack)) #两个引用地址不一样 print(id(Garen.attack)) |
---|
输出结果为:
1 2 | 1009949719304 1009951072464 |
---|
分析:g1.attack就是在执行Garen.attack的功能,python的class机制会将Garen的函数属性attack绑定给g1,g 1相当于拿到了一个指针,指向Garen类的attack功能。除此之外,g1.attack()会将g1传给attack的第一个参数。
三、对象(实例)
对象是关于类而实际存在的一个例子,即实例
#类实例化得到g1这个实例
1 2 3 4 5 6 7 8 9 10 | class Garen: camp='Demacia' def __init__(self,nickname,aggressivity=58,life_value=455): self.nickname=nickname #为自己的盖伦起个别名; self.aggressivity=aggressivity #英雄都有自己的攻击力; self.life_value=life_value #英雄都有自己的生命值; def attack(self,enemy): print("attack %s" % enemy) g1=Garen('草丛伦') |
---|
1、对象的属性引用和绑定方法
(1)对象(实例)只有一种作用:属性引用
格式: 实例名.类的变量名
实例名.绑定方法
实例名.实例自己的变量名
1 2 3 | print(g1.nickname) print(g1.aggressivity) print(g1.life_value) |
---|
输出结果为:
1 2 3 | 草丛伦 58 455 |
---|
(2)对象的属性操作
查看属性信息
1 | print(g1.nickname) |
---|
输出结果:
1 | 草丛伦 |
---|
修改属性信息
1 2 | g1.nickname="伦哥" print(g1.nickname) |
---|
输出结果为:
1 |
---|
添加属性
1 2 | g1.sex="female" print(g1.sex) |
---|
输出结果为:
1 | Female |
---|
删除属性:
1 2 | del g1.sex print(g1.sex) |
---|
输出结果为:
1 | AttributeError: 'Garen' object has no attribute 'sex' #报错 |
---|
(3)查看实例属性
同样是dir和内置__dict__两种方式
特殊实例属性
__class__
__dict__
(4)对象(实例)的绑定方法
对象本身只有数据属性,但是python的class机制会将类的函数绑定到对象上,称为对象的方法,或者叫绑定方法。
1 2 | print(g1.attack) #对象的绑定方法 print(Garen.attack) #对象的绑定方法attack本质就是调用类的函数attack的功能,二者是一种绑定关系 |
---|
输出结果为:
1 2 | <bound method Garen.attack of <__main__.Garen object at 0x00000017370815F8>> <function Garen.attack at 0x0000001737085048> |
---|
对象的绑定方法的特别之处在于:obj.func()会把obj传给func的第一个参数
2、对象的交互
仿照Garen类创建一个Riven类:
实例Riven类
交互:瑞雯攻击草丛伦
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class Riven: camp='Noxus' def __init__(self,nickname,aggressivity=54,life_value=414): self.nickname=nickname #为自己的瑞雯起个别名; self.aggressivity=aggressivity #英雄都有自己的攻击力; self.life_value=life_value #英雄都有自己的生命值; def attack(self,enemy): print("attack %s" % enemy) enemy.life_value -= self.aggressivity g1=Garen('草丛伦') r1=Riven('瑞雯') print(g1.life_value) r1.attack(g1) print(g1.life_value) |
---|
输出结果为:
1 2 3 | 455 瑞雯 attack 草丛伦 401 |
---|
3、 对象(实例)名称空间
创建一个对象(实例)就会创建一个对象(实例)的名称空间,存放对象(实例)的名字,称为对象(实例)的属性
在obj.name会先从obj自己的名称空间里找name,找不到则去类中找,类中找不到就找父类。最后找不到就抛出异常。