20201222-1 类的继承2

1-1-1
Man 在初始化时 可以多传入一个属性吗?
可以在类 Man 下进行重构

class People:

    def __init__(self,name,age):
        self.name = name    
        # 等号两边的 name 变量名可以不一致,比如 self.NAme = name; name 是(self,name,age)中的参数名,NAme 是赋的变量名
        self.age = age

    def eat(self):
        print("%s is eating..."%self.name)
    def talk(self):
        print("%s is talking..."%self.name)
    def sleep(self):
        print("%s is sleeping..."%self.name)
    
class Man(People):
    # def __init__ 这个动作相当于完全重构,会覆盖
    # 这样用户实例化时,不会调用父类,将直接调用这里的 def __init__
    # 这样需要重新写一遍参数
    def __init__(self,name,age,money):
        People.__init__(self,name,age) # self.name 和 age 在父类中实现
        self.money = money             # 新增功能 money 在子类中实现
        print("%s 一出生就有%s money"%(self.name,self.money))

    def piao(self):
        print("%s is piaoing.....20s......done."%self.name)
    def sleep(self):
        People.sleep(self)      
        print("man is sleeping")

class Woman(People):
    def get_birth(self):
        print("%s is born a baby...."%self.name)
        
m1 = Man("NiuHanYang",222,10)       # 这样就需要 传入 money   
m1.eat()
m1.piao()
m1.sleep()

w1 = Woman("ChenRonghua",26)
w1.get_birth()
--->
NiuHanYang 一出生就有 10 money
NiuHanYang is eating...
NiuHanYang is piaoing.....20s......done.
NiuHanYang is sleeping...
man is sleeping
ChenRonghua is born a baby....

这就是对 构造函数 进行重构
父类的参数都要写一遍,因为用户调用时,不是调用父类,是在调用初始化构造函数
写完后,加入新增的属性,这时候就与父类无关了
注:没有高级方法,只可以这样写

 

1-1-2
父类通常不会有很多参数,不固定的加 *args 即可
还有一种其他的方法可以调用父类,另一种方式,叫做 super
class People:

    def __init__(self,name,age):
        self.name = name    
        # 等号两边的 name 变量名可以不一致,比如 self.NAme = name; name 是(self,name,age)中的参数名,NAme 是赋的变量名
        self.age = age

    def eat(self):
        print("%s is eating..."%self.name)
    def talk(self):
        print("%s is talking..."%self.name)
    def sleep(self):
        print("%s is sleeping..."%self.name)
    
class Man(People):
    def __init__(self,name,age,money):
        # People.__init__(self,name,age) # self.name 和 age 在父类中实现
        super(Man,self).__init__(name,age)
        # super(Man,self).__init__(name,age) 这种写法与 People.__init__(self,name,age) 是完全一样的 
        # super 的作用就是 继承父类的 构造函数      
        self.money = money         
        print("%s 一出生就有%s money"%(self.name,self.money))

    def piao(self):
        print("%s is piaoing.....20s......done."%self.name)
    def sleep(self):
        People.sleep(self)      
        print("man is sleeping")

class Woman(People):
    def get_birth(self):
        print("%s is born a baby...."%self.name)
        
m1 = Man("NiuHanYang",222,10)       # 这样就需要 传入 money   
m1.eat()
m1.piao()
m1.sleep()

w1 = Woman("ChenRonghua",26)
w1.get_birth()
--->
NiuHanYang 一出生就有10 money
NiuHanYang is eating...
NiuHanYang is piaoing.....20s......done.
NiuHanYang is sleeping...
man is sleeping
ChenRonghua is born a baby....
1-1-3
既然 super(Man,self).__init__(name,age) 这种写法与 People.__init__(self,name,age) 是完全一样的
为什么还会有 super 呢?
super 没有写 People,这样以后修改父类名称时,super 无需修改
如果有多个子类,无需修改多个子类中的 "People" 

类可以进行多继承,比如:
class Man(People,Animal):
    def __init__(self,name,age,money):
        People.__init__(self,name,age)
        Animal.__init__(self,name,age)
        # 如果用 super 就会变得方便,直接多继承了
        super(Man,self).__init__(name,age)
1-1-4 
其实还有一个地方可以改进,其实标准的写法如下:
# 好比 python 2.7 和 3.0; 新式类中多了一些升级
# class People: 经典类
class People(object):  # 新式类
    def __init__(self,name,age):
        self.name = name    
        # 等号两边的 name 变量名可以不一致,比如 self.NAme = name; name 是(self,name,age)中的参数名,NAme 是赋的变量名
        self.age = age

    def eat(self):
        print("%s is eating..."%self.name)
    def talk(self):
        print("%s is talking..."%self.name)
    def sleep(self):
        print("%s is sleeping..."%self.name)
    
class Man(People):
    def __init__(self,name,age,money):
        # People.__init__(self,name,age) # self.name 和 age 在父类中实现
        super(Man,self).__init__(name,age)
        # super(Man,self).__init__(name,age) 这种写法与 People.__init__(self,name,age) 是完全一样的 
        # super 的作用就是 继承父类的 构造函数      
        self.money = money         
        print("%s 一出生就有%s money"%(self.name,self.money))

    def piao(self):
        print("%s is piaoing.....20s......done."%self.name)
    def sleep(self):
        People.sleep(self)      
        print("man is sleeping")

class Woman(People):
    def get_birth(self):
        print("%s is born a baby...."%self.name)
        
m1 = Man("NiuHanYang",222,10)       # 这样就需要 传入 money   
m1.eat()
m1.piao()
m1.sleep()

w1 = Woman("ChenRonghua",26)
w1.get_birth()

我们只需要关心,新式类多继承的方式变了
在继承上,新式类和经典类是有明显不同的
super(Man,self).__init__(name,age) 是新式类的写法
People.__init__(self,name,age) 是经典类的写法
1-2
经典类和新式类的变化,主要体现在继承上
首先需要了解多继承,才可以知道区别在哪里
不是所有语言都支持多继承,比如 java 就是不支持的

# 现在有一个 People,添加一个关系类
class People(object):  # 新式类
    def __init__(self,name,age):
        self.name = name    
        # 等号两边的 name 变量名可以不一致,比如 self.NAme = name; name 是(self,name,age)中的参数名,NAme 是赋的变量名
        self.age = age

    def eat(self):
        print("%s is eating..."%self.name)
    def talk(self):
        print("%s is talking..."%self.name)
    def sleep(self):
        print("%s is sleeping..."%self.name)

class Relation(object):
    # 结果生成两个人,调用的是 m1 的 friends;得有交朋友的对象,所以obj就是w1
    # 为什么这地方写的是 obj 而不是 "chenronghua",因为传的只是一个字符串,并没有真的关联
    # 真正要传的是 w1
    def make_friends(self,obj):
        print("%s is making friends with %s"%(self.name,obj.name))

# 在男人这里直接继承 Relation    
class Man(People,Relation):
    def __init__(self,name,age,money):
        # People.__init__(self,name,age) # self.name 和 age 在父类中实现
        super(Man,self).__init__(name,age)
        # super(Man,self).__init__(name,age) 这种写法与 People.__init__(self,name,age) 是完全一样的 
        # super 的作用就是 继承父类的 构造函数      
        self.money = money         
        print("%s 一出生就有%s money"%(self.name,self.money))

    def piao(self):
        print("%s is piaoing.....20s......done."%self.name)
    def sleep(self):
        People.sleep(self)      
        print("man is sleeping")
# 在Woman这里也继承 Relation;多写一个就是多继承一个
class Woman(People,Relation):
    def get_birth(self):
        print("%s is born a baby...."%self.name)
        
m1 = Man("NiuHanYang",222,10)       # 这样就需要 传入 money   
# 既然继承了,就代表可以用 Relation 里的方法
w1 = Woman("ChenRonghua",26)
m1.make_friends(w1)
--->
NiuHanYang 一出生就有10 money
NiuHanYang is making friends with ChenRonghua

这样就可以多继承了
这个 Relation 并没有写构造函数,也没有传参数,为什么就可以直接 .name了呢?
在继承父类时,name就已经传进去了,名字已经有了,所以不需要在继承一遍
只需要把额外的需要继承的功能填进去就可以了
自己已经有一些功能了,在添加一些新功能还是给自己添加,所以Relation中,可以 self.name,因为已经有名字了
1-2-1
这是因为 People 类中,已经先有名字了吗?
如果调用 People 和 Relation 的顺序呢?
class People(object):  # 新式类
    def __init__(self,name,age):
        self.name = name    
        # 等号两边的 name 变量名可以不一致,比如 self.NAme = name; name 是(self,name,age)中的参数名,NAme 是赋的变量名
        self.age = age

    def eat(self):
        print("%s is eating..."%self.name)
    def talk(self):
        print("%s is talking..."%self.name)
    def sleep(self):
        print("%s is sleeping..."%self.name)

class Relation(object):
    def make_friends(self,obj):
        print("%s is making friends with %s"%(self.name,obj.name))

# 在男人这里直接继承 Relation    
class Man(Relation,People):
    def __init__(self,name,age,money):
        # People.__init__(self,name,age) # self.name 和 age 在父类中实现
        super(Man,self).__init__(name,age)
        # super(Man,self).__init__(name,age) 这种写法与 People.__init__(self,name,age) 是完全一样的 
        # super 的作用就是 继承父类的 构造函数      
        self.money = money         
        print("%s 一出生就有%s money"%(self.name,self.money))

    def piao(self):
        print("%s is piaoing.....20s......done."%self.name)
    def sleep(self):
        People.sleep(self)      
        print("man is sleeping")
# 在Woman这里也继承 Relation;多写一个就是多继承一个
class Woman(People,Relation):
    def get_birth(self):
        print("%s is born a baby...."%self.name)
        
m1 = Man("NiuHanYang",222,10)       # 这样就需要 传入 money   
# 既然继承了,就代表可以用 Relation 里的方法
w1 = Woman("ChenRonghua",26)
m1.make_friends(w1)
--->
NiuHanYang 一出生就有10 money
NiuHanYang is making friends with ChenRonghua

# 结果依然是成立的
# 不过,class Man(Relation,People), Relation 和 People 的放置顺序,其实是有关系的
# 真正生成名字,不是在People里生成的,是在 Man 中构造时 生成的
# 本来要继承父类的 __init__ ;但是 Man 自己有 __init__ 了,所以就不执行父类的了,这里执行的是自己的
# 所以是先执行了自己的 __init__ 之后,由执行了父类的方法
# 所以,name就已经有了
1-2-2
如果Man没有自己的构造方法呢?这时就需要寻找父类的构造方法
类Man 先 Relation,后 People 能否找到呢?
class People(object):  # 新式类
    def __init__(self,name,age):
        self.name = name    
        self.age = age
    def eat(self):
        print("%s is eating..."%self.name)
    def talk(self):
        print("%s is talking..."%self.name)
    def sleep(self):
        print("%s is sleeping..."%self.name)

class Relation(object):
    def make_friends(self,obj):
        print("%s is making friends with %s"%(self.name,obj.name))
 
class Man(Relation,People):
    def piao(self):
        print("%s is piaoing.....20s......done."%self.name)
    def sleep(self):
        People.sleep(self)      
        print("man is sleeping")

class Woman(People,Relation):
    def get_birth(self):
        print("%s is born a baby...."%self.name)
        
m1 = Man("NiuHanYang",222)       
w1 = Woman("ChenRonghua",26)
m1.make_friends(w1)
--->
NiuHanYang is making friends with ChenRonghua

结果依然没有报错,为什么?
因为 Man 没有构造方法,实例化时会找父类,先找到了 Relation,Relation中没有构造方法,为什么没有报错?
因为 Relation 中的 make_friends 方法还没有执行,没执行所以没问题
1-2-3
可以进行验证
class People(object):  # 新式类
    def __init__(self,name,age):
        self.name = name    
        self.age = age
    def eat(self):
        print("%s is eating..."%self.name)
    def talk(self):
        print("%s is talking..."%self.name)
    def sleep(self):
        print("%s is sleeping..."%self.name)

class Relation(object):
    def __init__(self):
        print(self.name)
    # 验证,是不是按照从左到右的顺序执行的,如果是从左到右执行的,是会报错的
    def make_friends(self,obj):
        print("%s is making friends with %s"%(self.name,obj.name))
 
class Man(Relation,People):
    def piao(self):
        print("%s is piaoing.....20s......done."%self.name)
    def sleep(self):
        People.sleep(self)      
        print("man is sleeping")

class Woman(People,Relation):
    def get_birth(self):
        print("%s is born a baby...."%self.name)
        
m1 = Man("NiuHanYang",222)       
w1 = Woman("ChenRonghua",26)
m1.make_friends(w1)
--->
TypeError: __init__() takes 1 positional argument but 3 were given
报错中说,传了三个参数,虽然继承了父类,但是子类需要传参数
class Relation(object):
    def __init__(self):
        print(self.name)
里面必须接收参数
1-2-4
所以传入两个参数 n1 n2
class People(object):  # 新式类
    def __init__(self,name,age):
        self.name = name    
        self.age = age
    def eat(self):
        print("%s is eating..."%self.name)
    def talk(self):
        print("%s is talking..."%self.name)
    def sleep(self):
        print("%s is sleeping..."%self.name)

class Relation(object):
    def __init__(self,n1,n2):
        print(self.name)
    # 验证,是不是按照从左到右的顺序执行的,如果是从左到右执行的,是会报错的
    def make_friends(self,obj):
        print("%s is making friends with %s"%(self.name,obj.name))
 
class Man(Relation,People):
    def piao(self):
        print("%s is piaoing.....20s......done."%self.name)
    def sleep(self):
        People.sleep(self)      
        print("man is sleeping")

class Woman(People,Relation):
    def get_birth(self):
        print("%s is born a baby...."%self.name)
        
m1 = Man("NiuHanYang",222)       
w1 = Woman("ChenRonghua",26)
m1.make_friends(w1)
--->
AttributeError: 'Man' object has no attribute 'name'
这个时候报错说里面没有 name 
所以,默认的执行顺序是 从左到右;这时左边还没有这个 name,所以就没有 name 
1-3
# class People: 经典类
class People(object):  # 新式类
    def __init__(self,name,age):
        self.name = name    
        self.age = age
        self.friends = []   # 默认的朋友列表

    def eat(self):
        print("%s is eating..."%self.name)
    def talk(self):
        print("%s is talking..."%self.name)
    def sleep(self):
        print("%s is sleeping..."%self.name)

class Relation(object):
    def make_friends(self,obj):
        print("%s is making friends with %s"%(self.name,obj.name))
        self.friends.append(obj)
# 现在 Relation 和 People 没关系,通过子类继承才有关系
# 这样加上 obj 两个人就真正联系起来了

class Man(Relation,People):
    def __init__(self,name,age,money):
        # People.__init__(self,name,age) # self.name 和 age 在父类中实现
        super(Man,self).__init__(name,age)
        # super(Man,self).__init__(name,age) 这种写法与 People.__init__(self,name,age) 是完全一样的 
        # super 的作用就是 继承父类的 构造函数      
        self.money = money         
        print("%s 一出生就有%s money"%(self.name,self.money))

    def piao(self):
        print("%s is piaoing.....20s......done."%self.name)
    def sleep(self):
        People.sleep(self)      
        print("man is sleeping")

class Woman(Relation,People):
    def get_birth(self):
        print("%s is born a baby...."%self.name)
        
m1 = Man("NiuHanYang",222,10)       # 这样就需要 传入 money   
w1 = Woman("ChenRonghua",26)

m1.make_friends(w1)
print(m1.friends)
--->
NiuHanYang 一出生就有10 money
NiuHanYang is making friends with ChenRonghua
[<__main__.Woman object at 0x0000021283609C08>]

# obj.name 是字符串

 

posted @ 2020-12-22 19:37  Malakh  阅读(120)  评论(0编辑  收藏  举报