目录:https://www.jianshu.com/p/863c446364a8
一、类的空间问题
1、添加对象属性
(1)在类外面添加对象属性
class A:
address="河北张家口"
def __init__(self,name):
self.name=name
obj=A("Danny") #将Danny
obj.age=18 #在类外边添加对象属性
print(obj.__dict__)
运行结果:
{'name': 'Danny', 'age': 18}
(1)在类内部添加对象属性
class A:
def __init__(self,name):
self.name=name
def func(self,sex):
if self.name=="Danny":
self.sex=sex #添加对象属性
obj=A("Danny")
obj.func("男")
print(obj.__dict__)
运行结果:
{'name': 'Danny', 'sex': '男'}
注:对象的属性不仅可以在__init__里面添加,还可以在类的其他方法或者类的外面添加。
2、添加静态属性
(1)在类外部添加静态属性
class A:
address="河北张家口"
def __init__(self,name):
self.name=name
A.hobby="读书" #在类外部添加静态属性
print(A.__dict__)
运行结果:
{'__module__': '__main__', 'address': '河北张家口', '__init__':
, '__dict__': , '__weakref__': , '__doc__': None, 'hobby': '读书'}
(2)在类内部添加静态属性
class A:
def __init__(self,name):
self.name=name
def func(self,sex):
if self.name=="Danny":
self.sex=sex
def func1(self):
A.aaa="beautiful" #类内部添加静态属性
obj=A("Danny")
A.func1(111)
print(A.__dict__)
运行结果:
{'__module__': '__main__', '__init__':
, 'func': , 'func1': , '__dict__': , '__weakref__': , '__doc__': None, 'aaa': 'beautiful'}
注:类的静态属性不仅可以在类内部添加,还可以在类的外部添加。
3、从空间角度研究类
class Person:
mind="有思想"
activity="多样活动"
def __init__(self,name,age):
self.name=name
self.age=age
def work(self):
print("人类一般都需要工作")
#1、实例化对象,在内存中创建对象空间p1,这个对象空间不为空,而是有一个类对象指针(相当于指示牌)。
2、自动执行__init__方法,并且将对象空间p1传给self参数。
3、执行__init__方法里面的代码,给对象空间封装其属性。
p1=Person("Jenny",20)
#用对象查找属性
print(p1.mind)
#运行结果:
有思想
#更改属性
p1.mind="无脑"
print(p1.mind)
运行结果:
无脑
#执行到这里时我们误以为我们更改了属性,从下边的查询我们可以看到"真相"。
print(Person.mind)
print(p1.__dict__)
运行结果:
有思想
{'name': 'Jenny', 'age': 20, 'mind': '无脑'}
#从上边的运行结果可以发现我们更改的并不是属性,其实是在对象空间增加了p1.mind="无脑"属性。
del p1.mind
#当对象删除属性时,运行结果报错。不难发现对象只能查询属性,并不能对属性进行增删改操作。
总结:
1、对象查找属性的顺序:先从对象空间找 ------> 类空间找 ------> 父类空间找 ------->.....
类名查找属性的顺序:先从本类空间找 -------> 父类空间找--------> ........
上面的顺序都是单向不可逆,类名不可能找到对象的属性。
2、对象与对象之间原则上互相独立(除去组合这种特殊的关系之外)
二. 类与类之间的关系
在⾯向对象的世界中. 类与类中存在以下关系:
1、依赖关系
2、关联关系
3、组合关系
4、聚合关系
5、实现关系
6、继承关系
然而在Python中只存在三种关系:依赖关系、组合关系(组合、聚合、关联关系合并在了一起)、继承关系。
首先我们先学习依赖关系:
1、依赖关系
定义:
依赖关系:将一个类的类名或者对象传给另一个类的方法中
我们设计一个场景---大象把自己关进冰箱,在这件事情中,有两个事物,一个是大象,另外一个是冰箱。大象为主动把自己关进冰箱,冰箱被动操作。
class Elephant: #定义一个类为大象类
def __init__(self,name):
self.name=name #实例化类时,要传入大象的名称 name
def open(self,ref1): #ref1接受冰箱类的实例化对象
print(f"{self.name}默念三声:芝麻开门") #大象为动作发起的主体
ref1.open_door() #此时的ref1为冰箱类对象ref,冰箱类对象ref调用open_door方法
def close(self,ref1):
print(f"{self.name}默念三声:芝麻关门")
ref1.close_door()
class Refrigerator: #定义一个冰箱类
def __init__(self,name):
self.name=name
def open_door(self): #此时的方法在大象类中open 方法中调用,执行print语句
print(f"{self.name}冰箱门被打开了......")
def close_door(self):
print(f"{self.name}冰箱门被关上了......")
ele=Elephant("彩宝拉") #实例化对象,将"彩宝拉"传给"name"
ref=Refrigerator("海尔")
ele.open(ref) #大象类的实例化对象调用open方法,将冰箱类对象ref传给ref1
ele.close(ref) #这里的调用同理
运行结果:
彩宝拉大象默念三声:芝麻开门
海尔冰箱门被打开了......
彩宝拉大象默念三声:芝麻关门
海尔冰箱门被关上了......
#此时我们说大象和冰箱之间就是依赖关系,大象需要冰箱时操纵冰箱,但是冰箱并不属于大象。
2、组合关系
定义:
组合关系:将一个类的对象封装成另一个类的对象属性
假设情景,我们现在有两个类,一个是男孩类,一个是女孩类,这两个类之间本来没有关系,当他们成为男女朋友时,她们之间就有了相互的关系。男孩可以邀请女孩一起吃饭,女孩可以让男孩陪她逛街。
class Boy:
def __init__(self,name):
self.name=name
def meet(self,friend=None):
self.friend=friend #self.friend=zhen对象空间
def have_dinner(self): # self =Li这个对象空间
if self.friend:
print(f"{self.name}请{self.friend.name}一起吃饭")
self.friend.shopping(self) #相当于zhen.shopping 这里的参数self是Li对象空间
else:
print(f"{self.name}自己吃饭")
class Girl:
def __init__(self,name,age):
self.name=name
self.age=age
def shopping(self,boy_friend):#上边的参数self传给了boy_friend,此时的boy_friend为Li对象空间
print(f"{boy_friend.name}和{self.name}一起去购物")
Li=Boy("李明")
Zhen=Girl("珍妮",20) #实例化两个对象
Li.meet(Zhen) #对象Li调用meet方法,将zhen对象传入meet方法中
Li.have_dinner()
运行结果:
李明请珍妮一起吃饭
李明和珍妮一起去购物
总结:这种写法和依赖关系最大的不同点在于这两个类的命名空间都是你中有我,我中有你,类的传递不在是单单的给了一个对象方法,而是给了一个对象属性,增加了两个类之间的耦合。
接着我们来举一个更加形象的例子。
在这个例子中有角色类,有武器类,这个例子将实例化出两个角色,两把武器。在实例化对象的角度完成类的组合。
class GameRole:
def __init__(self,name,ad,hp):
self.name=name
self.ad=ad
self.hp=hp
def attack(self,p1):
p1.hp=p1.hp-self.ad
print(f"{self.name}攻击了{p1.name},{p1.name}掉了{self.ad}血,还剩{p1.hp}血")
class Weapon:
def __init__(self,name,ad):
self.name=name
self.ad=ad
def weapon_attack(self,p1,p2):
p2.hp = p2.hp - self.ad - p1.ad
print('%s 利用 %s 攻击了%s,%s还剩%s血'\
%(p1.name,self.name,p2.name,p2.name,p2.hp))
盖论=GameRole("盖论",10,100)
剑豪=GameRole("剑豪",20,90)
great_sword=Weapon("大宝剑",30)
spear=Weapon("红缨枪",40)
great_sword.weapon_attack(盖论,剑豪)
运行结果:
盖论 利用 大宝剑 攻击了剑豪,剑豪还剩50血
#在这个例子中,运行结果虽然得到了我们想要的结果,但是发起调用的对象是武器,武器类和角色类并没有发生实际意义上的组合。
接着我们在改进一下。
class GameRole:
def __init__(self,name,ad,hp):
self.name=name
self.ad=ad
self.hp=hp
def attack(self,p1):
p1.hp=p1.hp-self.ad
print(f"{self.name}攻击了{p1.name},{p1.name}掉了{self.ad}血,还剩{p1.hp}血")
def equit_weapon(self,wea):
self.weapon=wea #wea==great_sword
class Weapon:
def __init__(self,name,ad):
self.name=name
self.ad=ad
def weapon_attack(self,p1,p2):
p2.hp = p2.hp - self.ad - p1.ad
print('%s 利用 %s 攻击了%s,%s还剩%s血'\
%(p1.name,self.name,p2.name,p2.name,p2.hp))
gailun=GameRole("盖伦",10,100)
jianhao=GameRole("剑豪",20,90)
great_sword=Weapon("大宝剑",30)
gailun.equit_weapon(great_sword) #依赖关系
gailun.weapon.weapon_attack(gailun,jianhao)
运行结果:
盖论 利用 大宝剑 攻击了剑豪,剑豪还剩50血
通过我们的改进在角色类中添加了equit_weapon方法来对武器类进行了组合,我们就可以通过角色类的实例化对象的 weapon 属性来调用武器类中发起攻击动作的方法weapon_attack。提高了这两个类的耦合性。
在下一节我们讲解类的继承。