1 类和对象
学习的课程是https://www.bilibili.com/video/BV1ts411n7p1,老师讲的很细致
传入对象的时候,传的到底是什么
class Home:
def __init__(self, area = 128):
self.area = area
self.items = []
self.light = 'on'
def __str__(self):
msg = ''
if len(self.items) > 0:
msg = '这个房子里有:' + ','.join([temp.getName() for temp in self.items])
msg += '\n这个房子剩余面积为:' + str(self.area)
return msg
def addItems(self, item):
self.area -= item.getArea()
self.items.append(item)
def testModifyObj(self):
self.items[0].name = '席梦思'
class Item:
def __init__(self, name, size):
self.name = name
self.area = size
def getArea(self):
return self.area
def getName(self):
return self.name
home = Home(200)
print(home)
bed1 = Item('大床', 4)
home.addItems(bed1)
print(home)
bed2 = Item('小床', 2)
home.addItems(bed2)
print(home)
home.testModifyObj()
print(home)
print(bed1.name)
这里我定义了两个类。一个是Home,一个是Item类。
home对象接收了bed1,作为参数的传入。
为了搞明白这里接收的bed1到底是数据还是内存地址,在Home类中定义了一个testModifyObj()方法
经过验证,当我在接收了bed1以后,更改我接收的对象的name属性,实际的bed1也发生了修改。
因此,传入的是内存地址。
这也提醒了我们要定义方法去访问和修改对象的属性
2 类的继承
还是老王开枪。这里新定义一个枪叫狙击枪( Ju ), 继承 Gun()类。定义了新的子弹Juzidan,定义了杀伤力属性。
定义类的代码如下:
class Ren:
def __init__(self, name):
self.name = name
self.xueliang = 100
self.gun = None
def anzidan(self, danjia, zidan):
print('开始装子弹...')
danjia.jinzidan(zidan)
def andanjia(self, gun, danjia):
print('开始安弹夹...')
gun.shangdanjia(danjia)
def naqiang(self, gun):
print(self.name+'拿起了'+gun.name)
self.gun = gun
def kaiqiang(self, huairen):
print(self.name + '对着'+huairen.name+'开了一枪')
self.gun.jifa(huairen)
def diaoxue(self, shashangli):
if self.xueliang>0:
self.xueliang -= shashangli
if self.xueliang<0:
self.xueliang = 0
print(self.name + '已经挂了')
else:
print(self.name + '已经挂了,浪费子弹')
def __str__(self):
return self.name + '的血量为:' + str(self.xueliang) + '/100'
class Danjia:
def __init__(self,name='弹夹', room=20):
self.room = room
self.name = name
self.zidanlist = []
def __str__(self):
return self.name + '的容量为:'+str(self.room) + ' 子弹数量为:'+ str(len(self.zidanlist)) + '/' + str(self.room)
def jinzidan(self, zidan):
if self.room > len(self.zidanlist):
self.zidanlist.append(zidan)
def shangzidan(self):
if len(self.zidanlist)>0:
zidan = self.zidanlist[-1]
self.zidanlist = self.zidanlist[:-1]
print(zidan.name +'已经上膛···')
return zidan
else:
print('子弹用尽')
class Zidan:
def __init__(self):
self.name = '子弹'
self.shashangli = 5
def kill(self, huairen):
huairen.diaoxue(self.shashangli)
class Qiang:
def __init__(self):
self.danjia = None
self.name = '步枪'
def __str__(self):
if self.danjia:
return self.name + '当前有弹夹'+ ' 弹夹的子弹个数为' + str(len(self.danjia.zidanlist))
else:
return self.name + '当前无弹夹'
def shangdanjia(self, danjia):
if not self.danjia:
self.danjia = danjia
def jifa(self, huairen):
zidan = self.danjia.shangzidan()
zidan.kill(huairen)
class Ju(Qiang):
def __init__(self):
self.name = '狙击枪'
self.danjia = None
def jifa(self, huairen):
if self.danjia.zidanlist[-1].name == '狙击子弹':
juzidan = self.danjia.shangzidan()
juzidan.kill(huairen)
else:
print('狙击枪需要配狙击子弹')
class Juzidan(Zidan):
def __init__(self):
self.name = '狙击子弹'
self.shashangli = 100
程序的运行如下:
laowang = Ren("老王")
huairen = Ren('坏人')
danjia = Danjia('1号弹夹', 20)
ju = Ju()
print(ju)
juzidan = Juzidan()
laowang.anzidan(danjia,juzidan)
laowang.andanjia(ju, danjia)
print(ju)
laowang.naqiang(ju)
print(ju)
print(huairen)
laowang.kaiqiang(huairen)
print(huairen)
'''
狙击枪当前无弹夹
开始装子弹...
开始安弹夹...
狙击枪当前有弹夹 弹夹的子弹个数为1
老王拿起了狙击枪
狙击枪当前有弹夹 弹夹的子弹个数为1
坏人的血量为:100/100
老王对着坏人开了一枪
狙击子弹已经上膛···
坏人的血量为:0/100
'''
学到的知识点:
1、在设计类的方法之间相互传递的时候,比如人,要设置一个枪的属性;枪要设置弹夹的属性;弹夹要设置子弹的属性。好处是在调用方法的时候不需要再额外传入一个对象,直接用self.attri调用这个对象。逻辑上更加完整。
2、在继承类的过程中,如果需要重新用 def __init__(self)重新初始化类的属性,那么无法局部修改,必须全部修改。比如我定义了Juzidan这个类。本来只想定义一个self.name = '狙击子弹' , 但是定义完以后就没有了shashangli的属性。
3 函数定义的可变输入 def func(*args, **kwargs)
*args, **kwargs 这两个都是用来接收函数的输入参数。不同点在于,前一个接收的一个变量数据,变量的类型不限。而后一个接收的是一个" = "连接的键值对。
举例说明:
def A(a, *args, **kwargs):
print(a)
print(args)
print(kwargs)
>>> A(1,2,3,4,c=10)
1
(2, 3, 4)
{'c': 10}
形参a 接收了 1
*args 接收了 非键值对的 2,3,4,以元组的形式传递进来
**kwargs 接收了 c=10,并且以字典的形式传递进来
注意:
c=10 b不能写成 'c'=10, 否则会报错 keyword can't be an expression
除此以外,在接收参数的时候, *和** 还有解包的作用。
例如:
>>> A(1,*[1,2,3],c=10)
1
(1, 2, 3)
{'c': 10}
可以看到,如果加上一个*,就相当于把这个列表的变量全部取出来。等价于A(1,1,2,3 ,c=10)
注意:由于集合set 本身是去重的,因此不能使用 A(1,*{2,2,2},c=10),这个结果等价于A(1,2,c=10)
>>> A(1,*{'b':2})
1
('b',)
{}
如果将 * 用在字典前面,结果是 只解析了 字典的key,没有保存字典的value
这个时候,要用**来解包
>>> A(1,**{'b':2})
1
()
{'b': 2}
也就是说, A(1,**{'b':2}) 等价于 A(1, b=2)
但是还要注意:输入的字典的key如果与函数的形参名一致,则不能用**来解包,只能作为一个整体传入到元组里。