1、场景:
玩过游戏。主人公,进入了一个场景,有10个小怪物是一样的。有攻击力,血(100格)。如果小怪物有多个数值需要管理,小怪物的血量、小怪物出现在屏幕的地点。

可以使用字典来进行记录:

{"blood":100,"location":"10,10"}
[[100,(10,10)]]

10 个小怪物。记住10个小怪物所有的变量在哪里,怎么操作?

写一些函数,来操作这些数据。
函数你实现的时候,你觉得需要实现哪些功能?

10个方法:所有操作的数据的方法

add_blood():
blood+=1

minus_blood():
blood-=1

move():
x-=10
y-=10

类的好处:

    1) 把数据封装到实例里面,用同一的规则来进行存取,保证数据的安全和一致性

    2)基于类,方便进行扩展 (设计模式)

    3)类相当于模板,可以通过构造函数做初始化,快速生成实例

 class soldier(): #小怪物的类

    """小怪物的类,类定义"""

    def __init__(self,blood,location_x,location_y):    #构造函数,用来传参,可以无参
        self.blood = blood
        self.location_x = location_x
        self.lcoation_y = location_y

    def add_blood(self,num):    #实例方法:方法中有self参数
        if self.blood<=100:
            self.blood+=num
            if self.blood>100:
                self.blood = 100

    def minus_blood(self,num):    #实例方法:方法中有self参数
        if self.blood>=0:
            self.blood-=num
            if self.blood<0:
                self.blood = 0

    def tell_blood(self):    #实例方法:方法中有self参数
        return self.blood

s1= soldier(100,10,10)    #实例化,传参
s2= soldier(90,10,20)    #实例化,传参
s3= soldier(80,10,30)    #实例化,传参

print(s1.tell_blood())    #调tell_blood函数,输出每个小怪物的血量
print(s2.tell_blood())
print(s3.tell_blood())
 
 

"""小怪物的类,类定义"""

class soldier():

    def __init__(self,blood,location_x,location_y):   #构造函数,用来传参,可以无参

        self.blood=blood

        self.location_x=location_x

        self.location_y=location_y

 

    def add_blood(self,num):                    #实例方法:方法中有self参数

        if self.blood<=100:

            self.blood+=num

            if self.blood>100:

                self.blood=100

        return self.blood

 

    def minus_blood(self,num):                   #实例方法:方法中有self参数

        if self.blood>=0:

            self.blood-=num

            if self.blood<0:

                self.blood=0

        return self.blood

 

    def tell_blood(self):                          #实例方法;方法中有self参数

        return self.blood

 

s1=soldier(89,10,10)       #实例化,用模板做出来的东西,传参

s2=soldier(67,10,20)       #实例化,用模板做出来的东西,传参

s3=soldier(23,10,30)       #实例化,用模板做出来的东西,传参

 

print(s1.add_blood(70))     #调用add_blood函数,给小怪物1加血

print(s2.minus_blood(80))   #调用minus_blood函数,给小怪2物减血

print(s3.add_blood(80))     #调用add_blood函数,黑小怪物3加血

运行结果:

E:\>python a.py

100

0

100

 

2、类:(相关数据存在一起,并且有一组操作相关数据的方法)

    1)数据(属性)
    2)方法(类里面写的函数叫做方法。)

类比说明:
生产杯子,杯子的模具(类),可以设定不同的参数来生产杯子。
设定好不同的参数(通过构造函数传参),生产出具体的杯子(实例化)。
类:soldier
实例化:传入不同的参数(调用构造函数)
s1
s2
s3

3、批量生成实例化对象

import math
class circle(object):    #object可写可不写

    def __init__(self,radius):
        self.radius = radius    #radius这个变量在构造函数里,是一个局部变量,走出构造函数,radius这个变量是不能使用的。如果要使用该变量值,需要存在一个带self.的变量中,才能在其他的类方法中使用该值
    def get_area(self):
        return math.pi*self.radius*self.radius    #self.XXX称作实例变量

    def get_perimeter(self):
        return 2*math.pi*self.radius

for i in range(1,6):
    a= circle(i)
    print(a.get_area())
    print(a.get_perimeter())

#self.xxxx实例变量
#在类里面定义的函数叫做方法

def add():#函数
  return a+b

 
4、类:封装了数据,和操作数据的规则,保证数据的安全。

1. 如果用列表存储数据:

 a=[1,2,3]  #只存正数的列表
 1)也可使用函数来限制输入的数字
def set(a,index,new_value):
    if new_value>=0:     #当输入的值>=0时,新值会替代原始数据
        a[index] = new_value

set(a,0,100)      #新输入的值为100大于0,替换a[0]的值    
print(a)
set(a,0,-50)    #新输入的值为-50,小于0.不会替换a[0]的值
print(a)

2)但是无法限制别人修改值

a[0]=-50      
print(a)
 

2. 用类来实现限制修改输入负数

 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    #当输入的不为负数时,替换a中的数据;两个下划线是私有变量,除了类中的实例方法可以访问,外部不可以直接访问和修改
    def get(self):
        return self.__value    #读取列表中的值

p= positive_num_list([1,2,3,4])    #a=[1,2,3,4]

p.__value[0]=-100    #类保护了数据被修改

运行结果:

AttributeError: 'positive_num_list' object has no attribute '__value'    


print(p.get())    #结果:[1, 2, 3, 4]

p.set(1,50)    #试图替换a[1]的值为50
print(p.get())   #读取替换后的值,结果:[1, 50, 3, 4]


print(set([1,1,2,2]))

结果:{1, 2}  #set集合去重

 

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.value[0]=-8                             #尝试修改数值

print(p.get())

运行结果:

E:\>python a.py

[-8, 2, 3, 4]                           #数据依然被是修改成功,说明私有变量的重要性

 

3.用类来限制修改半径:

 import math
class circle(object):

    def __init__(self,radius):
        if radius<=0:    #当输入值是<=0的数时,将输入值重新赋值为1
            self.radius = 1
        else:
            self.radius = radius
        

    def modify_radius(self,radius):    #可以定义一个方法,限制输入值是负数
        if radius<0:
            self.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.modify_radius(-2)    #调用modify_radius方法
print(c.get_area())
 
5、self
 class P:

    def __init__(self,value): #构造方法,初始化的
        self.value = value     #value局部变量,self.value叫做实例变量
p =P(10)
print(p.value)
p.value=-10
print(p.value)
 
 
 class P:

    def __init__(self,value): #构造方法,初始化的
        self.__value = value     #value局部变量,self.value叫做实例变量
p =P(10)
print(p.__value)    #私有变量
 
 
 class P:

    def __init__(self,value): #构造方法,初始化的
        self.__value = value     #value局部变量,self.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)
print(p.get())    #私有变量
 
 
 class P:

    def __init__(self,value): #构造方法,初始化的
        self.__value = value   #value局部变量,self.value叫做实例变量
    def get(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)

内存中的位置:A
P:类变量
类定义的方法

类中所有定义的方法,类变量,只有一份

实例在内存中:有0个,1个或多个
内存中的位置:b
p1的实例:self.__value=1

内存中的位置:c
p2的实例:self.__value=2

内存中的位置:d
p3的实例:self.__value=3

p1.get()--->p1的实例调用get的方法:调用的时候,会把内存位置b发送给类定义的方法P.get
self:是一个方法的参数,该参数传的值是内存b的位置

get方法从内存b的位置找到__value值,然后执行方法中的代码。

但是定义的时候:def get(self),有self参数,调用的时候p1.get(),没有self.

实际get拿到了self的地址(该方法在内存中的位置b),找到了__value值

如果不把self的值传过去,找不到value所在的内存地址,方法执行失败


self传递的是某个实例的地址。实例地址里面的所有变量都可以在方法中进行使用。

 
 p3.set(1,2) #p3的地址传递给了self,1-》value,2是多余的。。
TypeError: set() takes 2 positional arguments but 3 were given
 
 
类中方法参数包含self的方法:实例方法
每个实例方法,只能操作本实例中的实例变量。

变量前面带有self.的叫做实例变量,可以在多个方法中访问,实例变量都存在对应的实例所在的内存地址中。

如果不加self.的叫做局部变量,不能跨方法访问

 

class P(object):

 

    def __init__(self,value):        #构造方法,初始化的

        value1=value           #value1和value局部变量,不能跨方法访问

    def get(self):

        return value1          #在这个方法中返回value1

 

p1=P(1)

print(p1.get())

运行结果

E:\>python a.py

Traceback (most recent call last):

  File "a.py", line 10, in <module>

    print(p1.get())

  File "a.py", line 7, in get

    return value1

NameError: name 'value1' is not defined  #value1未定义

 

总结:
 
 类:
   1 可以封装数据,制定数据的存储规则,保证数据的安全
   2 类相当于模板,可以通过构造函数做初始化,快速生成实例
   3 基于类,可以进行扩展。(设计模式)
   4 内存中存储的类变量和方法,只有一份。每个类的实例,都在内存中有一个地址(类产生的实例可以有0个、1个或多个)
   5 类中定义的实例方法(方法中有self参数),可以操作每个实例中封装的变量
   6 实例变量(self.开头的)可以在不同的实例方法中被访问。实例变量都存在对应的实例所在的内存地址中。
   7 __变量是私有变量,除了类中的实例方法可以访问,外部不可以直接访问和修改。