python--面向对象、类与类之间的关系(依赖、组合、继承)

依赖

依赖关系:将一个类名或对象名传给另一个类的方法中

class A:
    def __init__(self,name,age):
        self.name = name
        self.age= age

    def func(self,objb): #objb = b
        print(self)
        print(objb)
        objb.func()  #可以调用B类中的属性

class B:
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def func(self):
        print(self)
        
#实例化两个对象
a = A('小明',23)
b = B('小红',21)
a.func(b) #把b这个对象传给A类的func方法

组合

组合关系:将一个类的对象封装给另一个类的对象的属性

class A:
    def __init__(self,name):
        self.name = name 


    def func(self,obj):
        self.obj = obj #给一个类封装一个属性,该属性是另一个类的对象b
        #print(self.obj.name)

class B:
    def __init__(self,name):
        self.name = name

a = A('xm')
b = B('xh')
a.func(b)
print(a.__dict__)

继承

继承:子类可以具有父类的属性以及方法。
继承分为单继承和多继承:
单继承

class Animal:

    live = '活着不好吗'
    #就算父类这里不指定__init__,Animal也默认是继承了object(python中的新式类,在python2.2-2.7之间存在经典类(父类默认不继承object)和新式类),2.2之前都是经典类),
    #所以,当实例化对象之后也会自动执行__init__
    def __init__(self,name,age,gender):
        self.name = name
        self.age = age
        self.gender = gender

    def eat(self):
        print('吃饭了吗?')

class Persion(Animal): #继承
    def eat(self):  #当子类又写一个跟父类同名的方法时,
                    #先从对象空间找再从子类空间找(名字),最后从父类空间找
                    #找到只执行一次就不往上执行了
        print('吃面条')

p1 = Persion('小猪',2,'公') #虽然Persion没有__init__但是必须传参数,因为继承了父类(也叫基类或超类)
print(p1.__dict__) #{'name': '小猪', 'age': 2, 'gender': '公'} #子类获得了父类的属性
# p1.eat() #打印:吃饭了吗?#1.当子类没有eat方法时去执行父类的eat方法,如果在子类写一个与父类同名的eat方法叫:子类重写父类的方法
#3.再执行一下
p1.eat() #打印:吃面条

当子类和父类都存在同名的方法时,默认只执行一次,打印了吃面条之后就不打印吃饭了吗?了,要想执行了子类的方法之后又执行父类的方法:

class Animal:
    def __init__(self,name,age,gender):
        self.name = name
        self.age = age
        self.gender = gender

    def eat(self):
        print('动物吃东西')

class Persion(Animal):
    def __init__(self,name,age,gender,hoby):
        #方法一:直接调用,简单粗暴
        Animal.__init__(self,name,age,gender)  #直接调用父类的方法,通过对象p1传参
        #方法二:python内置的super
        # super(Persion, self).__init__()#传Animal中init所需参数
        super().__init__('小猪',2,'不详')
        self.hoby = hoby

    def eat(self):
        print('人类吃东西')
        #同时也执行父类的eat方法
        super().eat()
p1 = Persion('小明',23, '男','篮球')  #
# print(p1.__dict__)
p1.eat()
#人类吃东西
#动物吃东西

多继承

class O:
    pass

class D(O):
    pass

class E(O):
    pass


class F(O):
    pass


class B(D,E):
    # pass
    def eat(self):
        print('吃饭')

class C(E,F):
    pass

class A(B,C):
    # pass
    def eat(self):
        print('吃饭了吗')
ls = A()
ls.eat()
print(A.mro()) #查看执行顺序
#吃饭了吗

在多继承中,如果两个父类中出现两个同名的方法,那么子类是如何查找父类的方法的?即MRO(Method Resolution Order)问题。
mro计算公式:

mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )
(其中Child继承自Base1, Base2)

以上代码中,查找eat方法的顺序计算方法如下:

mro(A) = mro(A,(B,C))
       = [A] + merge(mro(B),mro(C),[B,C])
       = [A] + merge([B,D,E,O],[C,E,F,O],[B,C])
       = [A,B] + merge([D,E,O],[C,E,F,O],[C])
       = [A,B,D] + merge([E,O],[C,E,F,O],[C])#E在其它列表的表尾中,忽略此列表,进行下一个列表计算;C不在在其它列表的表尾中,拿出C放到merge外面,并移除C
       = [A,B,D,C] + merge([E,O],[E,F,O])
       = [A,B,D,C.E] + merge([O],[F,O])
       = [A,B,D,C.E,F] + merge([O],[O])
       = [A,B,D,C.E,F,O] #最终查找顺序
       

mro(B) = mro(B,(D,E))
       = [B] + merge(mro(D),mro(E),[D,E])
       = [B] + merge([D,O],[E,O],[D,E]) #表头D不在其他列表的表尾的集合中,拿出D放到merge外面,并移除D
       = [B,D] + merge([O],[E,O],[E]) 
       = [B,D,E] + merge([O],[O])
       = [B,D,E,O]
       
mro(C) = mro(C,(E,F)) 
       = [C] +merge(mro(E),mro(F),[E,F])
       = [C] +merge([E,O],[F,O],[E,F])
       = [C,E] +merge([O],[F,O],[F])
       = [C,E,F] +merge([O],[O])
       = [C,E,F,O]

python虽然支持多继承,但是并不推荐使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值