首页 > 其他分享 >派生

派生

时间:2024-01-05 20:34:30浏览次数:15  
标签:__ name 派生 age init self def

派生

【一】什么是派生

  • 派生是指子类继承父类,派生出自己的属性与方法,并且重用父类的属性与方法

【二】派生的方法

  • 子类可以派生出自己新的属性,在进行属性查找时,子类中的属性名会优先于父类被查找
  • 例如每个老师还有职称这一属性
  • 我们就需要在Teacher类中定义该类自己的__init__覆盖父类的
  • 当然子类也可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类),需要注意的是,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准了。

​ 举例:

派生出自己新的属性,在进行属性查找时,子类中的属性名会优先于父类被查找

方法一:

class People:
    school = '希望小学'

    def __init__(self, name, sex, age):
        self.name = name
        self.sex = sex
        self.age = age


class Teacher(People):
    # 派生 : 派生出自己新的属性,在进行属性查找时,子类中的属性名会优先于父类被查找
    def __init__(self, name, sex, age, title):
        self.name = name
        self.sex = sex
        self.age = age
        self.title = title

    def teach(self):
        print('%s is teaching' % self.name)


# 只会找自己类中的__init__,并不会自动调用父类的
obj = Teacher('Tony', 'male', 18, '工人')

print(obj.name, obj.sex, obj.age, obj.title)
  • 很明显子类Teacher中__init__内的前三行又是在写重复代码
  • 若想在子类派生出的方法内重用父类的功能,有两种实现方式

【1】指名道姓的调用某一个类的函数

class People:
    school='希望小学'

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

    def tell(self):
        print('我叫%s,今年%s,我在%s上学。'%(self.name,self.age,self.school))

class student(People):
    def __init__(self,name,age,title):
        #父类的属性
        People.__init__(self,name,age)
        self.title=title

obj=student('张三',20,'学生')
print(obj.name,obj.age,obj.title)
#张三 20 学生

【2】超类(super())

  • 调用super()会得到一个特殊的对象
  • 该对象专门用来引用父类的属性
  • 且严格按照MRO规定的顺序向后查找
class People:
    school='希望小学'

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


class student(People):

    def __init__(self,name,age,title):
        super().__init__(name,age)
        self.title=title


obj=student('张三',20,'学生')
print(obj.name,obj.age,obj.title)
#张三 20 学生
  • 注意注意注意:使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表

【3】小结

  • 这两种方式的区别是:
    • 方式一是跟继承没有关系的,而方式二的super()是依赖于继承的
    • 并且即使没有直接继承关系,super()仍然会按照MRO继续往后查找
    • mro()
# A没有继承B
class A:
    def test(self):
        super().test()


class B:
    def test(self):
        print('from B')


class C(A, B):
    pass


# 在代码层面A并不是B的子类
# 但从MRO列表来看,属性查找时,就是按照顺序C->A->B->object,B就相当于A的“父类”
print(C.mro())
# [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]

obj = C()

# 属性查找的发起者是类C的对象obj
# 所以中途发生的属性查找都是参照C.mro()
obj.test()
# from B
  • obj.test()首先找到A下的test方法
    • 执行super().test()会基于MRO列表(以C.mro()为准)当前所处的位置继续往后查找()
    • 然后在B中找到了test方法并执行。
  • 关于在子类中重用父类功能的这两种方式
    • 使用任何一种都可以
    • 但是在最新的代码中还是推荐使用super()
#指名道姓
class A:
    def __init__(self):
        print('A的构造方法')
class B(A):
    def __init__(self):
        print('B的构造方法')
        A.__init__(self)


class C(A):
    def __init__(self):
        print('C的构造方法')
        A.__init__(self)


class D(B,C):
    def __init__(self):
        print('D的构造方法')
        B.__init__(self)
        C.__init__(self)

    pass
f1=D() #A.__init__被重复调用
'''
D的构造方法
B的构造方法
A的构造方法
C的构造方法
A的构造方法
'''
#使用super()
class A:
    def __init__(self):
        print('A的构造方法')
class B(A):
    def __init__(self):
        print('B的构造方法')
        super(B,self).__init__()


class C(A):
    def __init__(self):
        print('C的构造方法')
        super(C,self).__init__()


class D(B,C):
    def __init__(self):
        print('D的构造方法')
        super(D,self).__init__()

f1=D() #super()会基于mro列表,往后找
'''
D的构造方法
B的构造方法
C的构造方法
A的构造方法
'''

标签:__,name,派生,age,init,self,def
From: https://www.cnblogs.com/banchengyanyu/p/17948022

相关文章

  • python面向对象之派生、组合、抽象类、反射
    【派生】在子类派生的新方法中如何重用父类的功能?  【组合】(定义) (案例) (组合和继承的区别) 【抽象类】(定义) (案例) 实例化 (总结) 【反射】什么是反射 如何反射 实现反射机制的步骤 解决办法 ......
  • [C++ 从入门到精通] 17.基类与派生类关系的详细再探讨
    文章预览:一.派生类对象模型简述二.派生类构造函数三.既当父类又当子类(多继承)四.不想当基类的类final五.静态类型与动态类型六.派生类向基类的隐式类型转换七.父类子类之间的拷贝与赋值一.派生类对象模型简述若一个类,继承自一个父类(基类),那么该类称之为子类(派生类)。并且该......
  • 区块链钱包派生账户简介
    区块链钱包的派生账户是基于一种被称为“分层确定性钱包”(HierarchicalDeterministicWallet,缩写为HD钱包)的技术。这项技术的核心在于,它允许从一个单一的种子(seed)生成一系列的账户地址。以下是其主要特点:种子生成:HD钱包的所有地址都源自一个种子,通常是一串随机生成的数字或者......
  • 三. 继承和派生
    文章参考:《C++面向对象程序设计》✍千处细节、万字总结(建议收藏)_白鳯的博客-CSDN博客1.继承案例#include<iostream>#include<string>usingnamespacestd;classPerson{private: stringname; stringid_number; intage;public: Person(stringname1,stringi......
  • typeof只能检测数据类型,而不能检测从数据类型中派生的其他类型,数组为object派生对象,所
    typeof[]返回值为objecttypeof只能检测数据类型,而不能检测从数据类型中派生的其他类型,数组为object派生对象,所以依然返回objecttypeof判断引用类型数据,除了function以外都会判断成为objectfunctionfn(){console.log(1);}conso......
  • C++将派生类赋值给基类
    在C/C++中经常会发生数据类型的转换,例如将int类型的数据赋值给float类型的变量时,编译器会先把int类型的数据转换为float类型再赋值;反过来,float类型的数据在经过类型转换后也可以赋值给int类型的变量。数据类型转换的前提是,编译器知道如何对数据进行取舍。例如:inta=......
  • ServiceA不应该直接调用ServiceB派生的Dao方法
    ServiceA不应该直接调用ServiceB派生的Dao方法背景    服务层单元测试是指针对应用程序中服务层代码的测试。服务层通常包含业务逻辑和数据处理代码,因此服务层单元测试的目标是验证这些代码的正确性和可靠性。通过编写针对服务层方法的测试用例,并模拟服务层的依赖项,我们可......
  • MSF与CS互相派生
    目录CS与MSF互相派生CS派生给MSF使用CS建立监听MSF接收CS派生MSF派生给CS使用MSF建立监听CS与MSF互相派生CS派生给MSF使用CS建立监听创建CS监听端口利用创建的CS端口生成控制器设法传至受害机并进行运行,收到请求建立转发给MSF的监听端口MSF接收CS派生配置MSF使......
  • C++将派生类赋值给基类
    在C/C++中经常会发生数据类型的转换,例如将int类型的数据赋值给float类型的变量时,编译器会先把int类型的数据转换为float类型再赋值;反过来,float类型的数据在经过类型转换后也可以赋值给int类型的变量。数据类型转换的前提是,编译器知道如何对数据进行取舍。例如:inta=......
  • C++的基类和派生类构造函数
    基类的成员函数可以被继承,可以通过派生类的对象访问,但这仅仅指的是普通的成员函数,类的构造函数不能被继承。构造函数不能被继承是有道理的,因为即使继承了,它的名字和派生类的名字也不一样,不能成为派生类的构造函数,当然更不能成为普通的成员函数。在设计派生类时,对继承过来的成员变量......