类与类之间的关系
类与类中存在的关系:
1.依赖关系
2.关联关系
3.组合关系
4.聚合关系
5.继承关系
6.实现关系
python是一门弱类型编程语言,并且所有的对象之间其实都是多态关系,所有的东西都可以当做对象来使用。
一.依赖关系
依赖关系:我需要用你,但你不属于我,这种关系是最弱的。
例:把大象装进冰箱,创建大象、冰箱两个类
class Elephant:
def __init__(self,name):
self.name = name
def open(self,ref):
print('大象说:开门吧')
ref.open_door()
def close(self,ref):
print('大象说:关门吧')
ref.close_door()
def take(self):
print('大象走进冰箱')
class BingXiang:
def open_door(self):
print('冰箱:门开了')
def close_door(self):
print('冰箱:关好了')
r = BingXiang() # 造冰箱
el = Elephant('独立自主的大象') # 造大象
el.open(r) # 把冰箱当作参数传递进大象的类中,大象可以指定任何一个冰箱去进行操作
el.take()
el.close(r)
二.关联关系、组合关系、聚合关系
1.关联关系:两种事物必须是相互关联的,但是在某些特殊情况下是可以更改的和更换的。
2.聚合关系:属于关联关系中的一种特例,重点是xxx和xxx聚合城了xxx,各自有各自的声明周期,主体完蛋了,个体依然存在。
3.组合关系:属于关联关系中的一种特例,写法上差不多,组合关系比聚合关系还要紧密,主体完蛋了,个体跟着一起完蛋。
例:
男女朋友关系,可以是相互的也可以是单方面的
class Boy:
def __init__(self,name,girlFriend = None):
self.name = name
self.girlFriend = girlFriend
def yujian(self):
if self.girlFriend:
print('%s 和 %s 在一起吃饭' % (self.name,self.girlFriend.name))
else:
print('单身狗吃什么饭')
class Girl:
def __init__(self,name):
self.name = name
b = Boy('alex')
b.yujian()
g = Girl('王婆')
b.girlFriend = g # 有女朋友了
b.yujian() # 两个人一起吃饭
注:关联关系在逻辑上出现了,我需要你,你还要属于我,这种逻辑就是关联关系。
组合关系和聚合关系,代码上的差别不大,都是把另一类的对象作为这个类的属性来传递和保存,只是在含以上有不同。
三:继承关系
继承关系:子类在不影响父类的程序运行的基础上对父类进行扩充和扩展,我们可以父类成为超类或者基类,子类被称为派生类。
例:类名和对象默认是可以作为字典的key的
class Foo:
def __init__(self):
pass
def method(self):
pass
print(hash(Foo))
print(hash(Foo()))
# 既然可hash,那就说明字典的key可以是对象或者类
dic = {}
dic[Foo] = 123
dic[Foo()] = 456
print(dic) # {<class '__main__.Foo'>: 123, <__main__.Foo object at 0x00000000021D82E8>: 456}
四:self
接下来研究继承上的相关内容,主要研究self(不关方法之间如何进行调用,类与类之间是何关系,
默认的self都是访问这个方法的对象)
例1:
class Base:
def __init__(self, num):
self.num = num
def func1(self):
print(self.num)
class Foo(Base):
pass
obj = Foo(123)
obj.func1() # 123 运行的Base中的func1
例2:
class Base:
def __init__(self, num):
self.num = num
def func1(self):
print(self.num)
class Foo(Base):
def func1(self):
print("Foo. func1", self.num)
obj = Foo(123)
obj.func1() # Foo. func1 123 运⾏的是Foo中的func1
总结:self在访问方法的顺序:永远都是先找自己,自己找不到再到父类里找。
例3:
class Base:
def __init__(self, num):
self.num = num
def func1(self):
print(self.num)
self.func2()
def func2(self):
print(111, self.num)
class Foo(Base):
def func2(self):
print(222, self.num)
lst = [Base(1), Base(2), Foo(3)]
for obj in lst:
obj.func2() # 111 1 | 111 2 | 222 3
例4:
class Base:
def __init__(self, num):
self.num = num
def func1(self):
print(self.num)
self.func2()
def func2(self):
print(111, self.num)
class Foo(Base):
def func2(self):
print(222, self.num)
lst = [Base(1), Base(2), Foo(3)]
for obj in lst:
obj.func1() # 1 111 1 | 2 111 2 | 3 222 3
总结:self就是你访问方法的那个对象,先找自己的,然后在找父类的。
五:类中的特殊成员
像__init__()这样,带上下划线的方法就属于特殊成员,在特殊的场景会被自动执行。
例:
1. 类名() 会自动执⾏__init__()
2. 对象() 会自动执⾏__call__()
3. 对象[key] 会自动执⾏__getitem__()
4. 对象[key] = value 会自动执⾏__setitem__()
5. del 对象[key] 会自动执⾏ __delitem__()
6. 对象+对象 会自动执⾏ __add__()
7. with 对象 as 变量 会自动执⾏__enter__ 和__exit__
8. 打印对象的 时候 会自动执⾏ __str__
9. 干掉可哈希 __hash__ == None 对象就不可哈希了.
创建对象的真正步骤:
⾸先, 在执⾏类名()的时候,系统会自动先执⾏__new__()来开辟内存,此时新开辟出来的内存区域是空的。
紧随其后系统⾃动调⽤__init__()来完成对象的初始化⼯作,按照时间轴来算。
1.加载类
2.开辟内存(__new__)
3.初始化(__init__)
4.使用对象去执行什么