• Jingxiao 置顶
    2019-06-04
    思考题答案:庄小P 同学的写法很好,非常明确的表明了菱形继承潜在的问题:一个基类的初始化函数可能被调用两次。在一般的工程中,这显然不是我们所希望的。正确的做法应该是使用 super 来召唤父类的构造函数,而且 python 使用一种叫做方法解析顺序的算法(具体实现算法叫做 C3),来保证一个类只会被初始化一次。

    class A():
        def __init__(self):
            print('enter A')
            print('leave A')

    class B(A):
        def __init__(self):
            print('enter B')
            super().__init__()
            print('leave B')

    class C(A):
        def __init__(self):
            print('enter C')
            super().__init__()
            print('leave C')

    class D(B, C):
        def __init__(self):
            print('enter D')
            super().__init__()
            print('leave D')

    D()

    enter D
    enter B
    enter C
    enter A
    leave A
    leave C
    leave B
    leave D
    展开
    
     64
  • hlz-123
    2019-06-03
    第一个问题,面向对象编程四要素是什么?它们的关系又是什么?
    答:面向对象编程四要素是类,属性,函数,对象,
           它们关系可以总结为:类是一群具有相同属性和函数的对象的集合。
    第二个问题,讲了这么久的继承,继承究竟是什么呢?你能用三个字表达出来吗?
    三个字:父与子。儿子可以使用自己的东西,没有的可以使用父亲的东西。
    
     48
  • 庄小P
    2019-06-03
    class A():
        def __init__(self):
            print('A class called')

    class B(A):
        def __init__(self):
            print('B class called')
            A.__init__(self)
    class C(A):
        def __init__(self):
            print('C class called')
            A.__init__(self)
    class D(B,C):
        def __init__(self):
            print('D class called')
            B.__init__(self)
            C.__init__(self)
    d = D()
    ####输出
    D class called
    B class called
    A class called
    C class called
    A class called
    展开
    
     35
  • helloworld
    2019-06-04
    面向对象编程的四要素: 类、属性、函数(方法)、对象(实例)

    下面来展开总结:

    类: 一群有着相同属性和函数(方法)的对象(实例)的集合,也可以具象化的理解为是一群有着相似特征的事物的集合;用class来声明。
    抽象类:是一种特殊的类,只能作为父类存在,一旦对象化(或叫实例化)就会报错;一般使用class Classname(metaclass=ABCMeta)来声明。
    类的继承:子类继承父类,子类可以使用父类的属性和函数,同时子类可以有自己独特的属性和函数;子类在生成对象的时候(实例化时),是不会自动调用父类的构造函数的,必须在子类的构造函数中显示的调用父类的构造函数;继承的优势是减少重复代码,降低系统熵值(即复杂度)。

    属性:用"self.属性名"来表示,通过构造函数传入;表示对象(实例)的某个静态特征。
    私有属性:以__开头的属性,举例:self.__属性名,只能在类内部调用,类外部无法访问。
    公有属性:和函数并列声明的属性,可以理解为常量,一般用全大写表示;在类中通过"self.常量名"来调用,在类外使用"对象名.常量名"或者"类名.常量名"来调用。

    函数:表示对象(实例)的某个动态能力。
    构造函数:用def __init__(self, args...)声明,第一个参数self代表当前对象的引用,其他参数是在对象化时需要传入的属性值;构造函数在一个对象生成时(即实例化时)会被自动调用。
    成员函数:是正常的类的函数,第一个参数必须是self;可通过此函数来实现查询或修改类的属性等功能。
    静态函数:静态函数和类没有什么关联,第一个参数也没有什么特殊性;一般用来做一些简单独立的任务,既方便测试也能优化代码结构;一般使用装饰器@staticmethod来声明。
    类函数:类函数的第一个参数一般为cls,表示必须传一个类进来;最常用的功能是实现不同的init构造函数;需要装饰器@classmethod来声明。
    抽象函数:一般定义在抽象类中,主要目的是要求子类必须重载该函数才能正常使用;使用装饰器@abstractmethod来声明。
    函数重载:父类的某函数通过raise Exception的方式要求子类必须重写该函数来覆盖父类原有函数。

    对象:类对象化(实例化)后的某一个具体事物。
    展开
     5
     26
  • 不瘦到140不改名
    2019-06-03
    思考题:多重继承,是基于mro进行查找,使用的是一种C3的算法。总结一下规律就是:
    B F

    C G

    D H

    E I

      J
    在python3中,如果最顶层的两个类没有继承共同的类,那么查找顺序是,先从左找到头,再从右找到头,即,J->E->D->C->B->I->H->G->F

      A
    B F

    C G

    D H

    E I

      J
    如果继承了共同的类,也就是形成了菱形结构,那么查找顺序为,先从左找,只找到倒数第二层,然后从右找到头,即J->E->D->C->B->I->H->G->F->A
    展开
    
     21
  • 奔跑的蜗牛
    2019-06-03
    经典类:深度优先,F->D->B->A->E->C->H
    新式类:广度优先,F->D->B->E->C->H->A

    class A:
        # def test(self):
        # print('from A')
        pass
    class B(A):
        # def test(self):
        # print('from B')
        pass
    class C(A):
        # def test(self):
        # print('from C')
        pass

    class D(B):
        # def test(self):
        # print('from D')
        pass

    class E(C):
        # def test(self):
        # print('from E')
        pass

    class H(A):
        def test(self):
            print('from H')
        pass
    class F(D,E,H):
        # def test(self):
        # print('from F')
        pass
    f=F()
    f.test()
    print(F.mro())
    展开

    作者回复: 👍

     1
     12
  • LiANGZE
    2019-06-03
    只知道多重继承时会通过mro算法生成一个顺序,可以通过 xxx.__mro__ 查看继承的顺序,但其中原理确实没深入研究过 🤔
    
     10
  • Geek_59f23e
    2019-06-04
    哥,能不能教教怎么搭梯子?给的链接都是国外的,进不了咋整。。
     1
     8
  • DX3906
    2019-06-03
    init双下方法是初始化方法,构造方法是双下new
    
     5
  • 清风
    2019-06-09
    我到底该叫方法还是叫函数
    
     4
  • 爬行的蜗牛
    2019-06-07
    1. 面向对象编程的四要素是什么, 它们的关系是什么
    - 抽象
    - 封装
    - 继承
    - 多态
    个人理解:
    -抽象的本质是抽取不同类的的相同方法(函数)和属性, 作为父类的属性和方法;
    - 封装就是把功能封装抽象的方法和其他属性和方法;
    - 子类继承父类的抽象出来的属性和方法;
    - 多态就是重写抽象的方法(函数)。

    2. 继承是什么? 用三个字表示出来;
    子类继承父类的属性和方法(函数)减少代码量和复杂度;
    三个字:承接:属性&函数
    展开

    作者回复: 👍

    
     4
  • Fergus
    2019-06-03
    先写答案再看答案:
    Q1.面向对象编程四要素是什么?它们的关系又是什么?

    A. 类,实例(对象),属性,方法(函数);

    一般情况下,使用类前需要先实例化,即创建对象;属性是类实例化时由构造函数\_\_init__定义完成,表示类的静态特性,方法是类获取/修改类的属性的动作,表示类的动态能力;



    Q2.继承究竟是什么?

    A. “拿来用”

    Q3.菱形继承,BC 继承了 A,然后 D 继承了 BC,创造一个D 的对象。那么,构造函数调用顺序又是怎样的呢?

    A.

    ```
    class A():
        pass

    class B(A):
        pass

    class C(A):
        pass

    class D(B, C):
        pass

    d = D()
    ```

    展开
    
     3
  • Geek_00bd9e
    2019-06-06
    作者您好,引用您的例子,我想问个问题,执行到enter B的时候为什么没有输出enter A,B类不是继承了A类了吗? 反而输出enter C,然后才输出enter A。这个地方比较疑惑?
    class A():
        def __init__(self):
            print('enter A')
            print('leave A')

    class B(A):
        def __init__(self):
            print('enter B')
            super().__init__()
            print('leave B')

    class C(A):
        def __init__(self):
            print('enter C')
            super().__init__()
            print('leave C')

    class D(B, C):
        def __init__(self):
            print('enter D')
            super().__init__()
            print('leave D')

    D()

    enter D
    enter B
    enter C
    enter A
    leave A
    leave C
    leave B
    leave D
    展开
     3
     2
  • Fergus
    2019-06-05
    感谢老师对答案的补充,回头复习看到答案又增加了新知。
    
     2
  • 程序员人生
    2019-06-03
    类函数有什么特别之处?
    
     2
  • GLADIATOR
    2019-06-12
    老师,我有一个疑问:从C++和java来看,构造函数肯定是先执行父类再构造子类,根据您的例子只是把print放在了父类构造函数之前,所以看起来单继承是先子后父,单实际上通过调试可以看出,其实仍然是先父后子。
     1
     1
  • Geek_59f23e
    2019-06-04
    1. 类 对象 属性 函数
    2. DRY (don't repeat yourself)
    3. D B A C (C3算法)
    
     1
  • lllong33
    2019-06-04
    1、面向对象的四要素,关系?
    - 类、对象,属性,函数
    - 类是一群具有相同属性和函数的对象的集合。

    2、用三个词描述继承
    - 重构、多态、复用性

    3、多重继承,函数执行顺序
    - 遵循MRO(method resolution order)原则,从左至右使用顺序。
    参考:[调用父类方法](https://python3-cookbook.readthedocs.io/zh_CN/latest/c08/p07_calling_method_on_parent_class.html)
    展开
    
     1
  • Fergus
    2019-06-03
    对于思考题,感谢提到c3算法的小伙伴,给补充了知识。但可能过度解读老师的意图了吧
    
     1
  • enjoylearning
    2019-06-03
    写的真好,立马搞清楚了Python中的面向对象和抽象类,昨天还在看abcmeta怎么用,另外我觉得最佳实践里不提倡多重继承,感觉这样是代码坏味道

    作者回复: 正解,设置这道思考题的另一个意图是,对于自己不熟悉的地方,不要想当然就用在生产线上,能用简单的思路解决问题,就不要用自己不熟悉的复杂的特性。

    
     1
我们在线,来聊聊吧