12.1面向对象
12.1.1什么是类?
- 假设:有50双鞋,怎么去管理这50双鞋
进行分类:
10双运动鞋
10双皮鞋
10双凉鞋
10双拖鞋
10双童鞋
我会把每种鞋做一个分类,然后放到一个鞋柜里面。
class本质:分类管理
12.1.2面向对象编程:用类的方式来管理你的数据
Ø 图书:
历史:清朝、近代史、现代史……
计算机
文学
类:(相关数据存在一起,并且有一组操作相关数据的方法)
成员变量:属性
方法:操作成员变量(属性)类里面写的函数叫做方法。
Ø 游戏设计场景:
玩过游戏。主人公,进入一个场景,有10个小怪物
是一样的。有攻击力,血(100格)。如果小怪物有多个值需要管理,小怪物的血量、小怪物出现在屏幕的位置;
例如:
{“blood“:100,”location”:”10,10”}
[[100,(10,10)]]
假设小怪物有10个属性,那么我写10个字典,那么我写的10个字段,有100个值要管理
10个小怪物。记住10个小怪物所有的变量在哪里,怎么操作?
写一些函数,来操作这些数据。
函数你实现的时候,你觉得需要实现哪些功能?
10个方法:所有操作的数据方法
add_blood():
blood+=1
minus_blood():
blood-=1
move():
x-=10
y-=10
这些都是使用“类“来实现的
示例:
class soldier():
"""小怪物的类"""
def __init__(self,blood,location_x,location_y): #小怪物的属性
self.blood = blood #血量
self.location_x = location_x #x轴坐标
self.location_y = location_y #y轴坐标
def add_blood(self,num): #小怪物加血的方法
if self.blood<=100:
self.blood+=num
if self.blood>100:
self.blood = 100
def miuns_blood(self,num): #小怪物的掉血方法
if self.blood>=0:
self.blood-=num
if self.blood<0:
self.blood = 0
def tell_blood(self):
return self.blood
s1 = soldier(100,10,10) #实例化,用模板做出来的东西(相当于模具)
s2 = soldier(90,10,20)
s3 = soldier(80,10,30)
print(s1.tell_blood())
print(s2.tell_blood())
print(s3.tell_blood())
类:(相关数据存在一起,并且有一组操作相关数据的方法)
- 成员变量:属性(数据)
- 方法:操作成员变量(属性)类里面写的函数叫做方法。
类比说明:
生产杯子,杯子的模具(类),可以设定不同的参数来生产杯子。
设定好不同的参数(通过构造函数传参)
类:soldier
实例化:传入不同的参数(调用构造函数),关键字__init__构造函数
s1 传入的都是__init__构造的函数
s2
s3
Ø 圆的面积和周长:
self.xxx实例变量
def __init__(self,blood,location_x,location_y):
self.blood = blood
在类里面定义的函数叫做方法
import math
class circle(object):
def __init__(self,radius): 变量一个值,radius
self.radius = radius
def get_area(self):
return math.pi*self.radius*self.radius
def get_perimeter(self):
return 2*math.pi*self.radius
for i in range(1,6):
print(a)
print(a.get_area())
print(a.get_perimeter())
Ø 如果传入了一个负数,那么从数学角度来讲是非法的。
def add():#函数
return a+b
c = [1,3.14,6.28]
c[0]=-1
半径不允许设定为负数。
用类来限制修改半径为负数
示例:
import math
class circle(object):
def __init__(self,radius):
if radius<=0: #保障了数据的安全性
self.radius = 1
else:
self.radius = radius
def set_radius(self,radius): #只有调用这个方法下面的逻辑才会生效
if radius<0:
self.radius = abs(radius) #abs为函数,返回radius绝对值
elif radius == 0:
self.radius = 1
def get_area(self):
return math.pi*self.radius*self.radius
def get_perimeter(self):
return 2*math.pi*self.radius
c=circle(-1)
print(c.get_area())
c.set_radius(-2) #通过abs把-2转换成2
print(c.get_area())
类:
封装了数据,和操作数据的规则,保证数据的安全。
保存数据、修改数据、计算了只会输出数据,通过类的方式可以避免每一个步骤出现脏数据(不是唯一的,但是是一个比较好的方案)
总结:
1 生成实例的时候很方便,快速的把多个数据封装到类里面
2 操作数据的规则写在方法里面,然后修改任意的数据都需要去操作这个方法,保证这个数据不会改成脏数据
Ø 两件事情都需要做数据安全设定
1 实例化的时候
def __init__(self,radius):
if radius<=0:
self.radius = 1
else:
self.radius = radius
2 修改数据的时候
def set_radius(self,radius):
if radius<0:
self.radius = abs(radius)
elif radius == 0:
self.radius = 1
函数和类的区别
函数:数据可以被改变
a=[1,2,3,4] #只存正数的列表
def set(a,index,new_value):
if new_value >= 0: #通过if制定取值规则
a[index] = new_value #a[index],index在里面属于位置,传入的时候也只是代表位置信息,new_value代表传进来的值,通过a[index] = new_value这种方式对原列表a[位置]进行修改值
return a[index]
set(a,0,100)
print(a)
set(a,0,-50) #不会修改
print(a) #只会返回上一个正确变量100
a[0]=-50 #但是不能保证所有人都按照上面的规则,直接越过set类
print(a) #成功修改-50
返回[-50, 2, 3, 4]
类:数据安全
class positive_num_list(object):
def __init__(self,a):
self.__value = a
def set(self,index,value):
if value<0:
return
self.__value[index] = value
def get(self):
return self.__value
p= positive_num_list([1,2,3,4])
#p.set(0,100)
#print(p.get())
#p.set(0,-100)
#print(p.get())
p.__value[0] = -100 #__value[0]属于class类中的私有变量,这种方法不可以传参、修改
,私有变量外面是不能访问的
Traceback (most recent call last):
File "b.py", line 19, in <module>
p.__value[0] = -100
AttributeError: 'positive_num_list' object has no attribute '__value'
python内置函数和自定义函数是否冲突:
- 代码内容:
class positive_num_list(object):
def __init__(self,a):
self.__value = a
def set(self,index,value):
if value<0:
return
self.__value[index] = value
def get(self):
return self.__value
p= positive_num_list([1,2,3,4])
p.set(1,50) #p.set就等于类的命名空间,set只能在p.下面使用
print(p.get())
print(set([1,1,2,2])) #这set可以在全局使用
- 返回数据:
D:\>py -3 b.py
[1, 50, 3, 4]
{1, 2}
总结:这两者之间没有任何影响
类的解释:
class p():
pass
p=p()
print(p)
D:\>py -3 b.py
<__main__.p object at 0x0000015F47A25C18>
_main__:表示当前程序
.p:表示对象
Object:表示p类下面的实例
at 0x0000015F47A25C18:在某个内存的地址
value和self.value的解释:
class p():
def __init__(self,value): #构造方法,初始化的
self.__value = value #value局部变量,
#self.value叫做实例变量,加入__ value便为了私有变量,
外面不能访问;
p=p(10)
print(p.value)
通过制定方法规则实现外部访问修改__ value
class p():
def __init__(self,value): #实际场景中不需要传参数可以不写
self.__value = value
def get(self): #制定实例访问方法
return "***: " + str(self.__value ) #访问规则
def set(self,value): #制定实例修改方法
if isinstance(value,(int,float)): #修改规则
self.__value = value
return None
p=p(10) 给类变量
print(p.get())
p.set("a") #修改规则不符,无法修改
print(p.get())
p.set(-5) #符合规则访问set方法进行修改变量
print(p.get())
self的作用:
class p():
def __init__(self,value):
self.__value = value
def get(self): #self传递位置
return "***: " + str(self.__value )
def set(self,value):
if isinstance(value,(int,float)):
self.__value = value
return None
p1 =p(1)
p2 =p(2)
p3 =p(3)
print(p1)
print(p2)
print(p3)
D:\>py -3 b.py
<__main__.p object at 0x0000028FC6BF45F8>
<__main__.p object at 0x0000028FC6BF4630>
<__main__.p object at 0x0000028FC6BF4668>
内存存中的位置:A
P:变量
类定义的方法
类中所有定义的方法,类变量,只有一份
实例在中内存中:有0个,1个活多个。
内存中的位置:b
p1的实例:self:__value=1
内存中的位置:c
p2的实例:self:__value=2
内存中的位置:d
p3的实例:self:__value=3
self的使用情况:
p1.get()--->调用的时候会把位置b发送给类定义的方法
self:是一个方法参数,内存位置b
get方法从内存b的位置找到,__value值,然后执行方法中的代码。
self传递的是某个实例的地址。实例地址里面的所有变量都可以在方法中进行使用。
print(p1)
print(p2)
print(p3)
p3.set(1,2) #p3的地址传递给了(self,1) -->value,2是多余的。。
对应的错误信息:
TypeError: set() takes 2 positional arguments but 3 were given
类总结:
1)把数据封装到实例里面,同统一的规则来进行存取,保证了数据的安全和一致性。
2)方便进行扩展
变量前面加self.的叫做实例变量
如果不加self.的叫局部变量
class p():
def __init__(self,value): #构造方法,初始化的
self.value1 = value #局部变量不能跨方法访问
#value和value局部变量,不能跨方法访问
print("构造函数:%s"%self.value1)
#self.value叫做实例变量
def get(self): #实例方法
return self.value1
p1 =p(1)
print(p1.get()) #局部变量不能跨方法访问
类:
1可以封装数据,制定数据的存储规则,保证数据的安全
2 类相当于模板,可以通过构造函数做初始化,快速生成实例
3 基于类,可以进行扩展。设计模式:“”“通过”面向对象”的方式设计很多种程序上数据访问的技巧”“”
4 实例方法内存中存储的类变量和方法,只有一份。每个类的实例,都在内存中有一个地址(实例可以有0个,1个或多个)
5 类中定义的实例方法(方法中有self参数),可以操作每个实例中封装的变量
6 实例变量(self.开头的)可以在不同的实例方法中被访问。
每个实例变量都存在对应的实例所在的内存地址中。
7 __变量是私有变量,除了类中的实例方法访问,外部不可以直接访问和修改