python3 中类的面向对象特性

封装,继承,多态,动态生成类

封装

python类中的封装特性是通过命名来实现的

  • private 用双下划线开头,表示变量或者函数只在当前类中可见
  • protect 用单下划线开头,表示变量或者函数只在当前类以及其子类中可见
  • public 不以下划线开头,表示变量或者函数可以在任意类中使用

继承

  1. 继承多个类

    class myClass(cls1,cls2):
        pass
  2. super机制

    • super() 函数用于调用下一个父类(超类)并返回该父类实例的方法。
    • 直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。总之前人留下的经验就是:保持一致性。要不全部用类名调用父类,要不就全部用 super,不要一半一半。
    super(type[, object-or-type])type指的是子类,object-or-type一般是self
  3. 经典类和新式类的方法解析顺序(MRO,Method Resolution Order)

    • 经典类,类自身或者其 Python 2.x中默认都是经典类,只有显式继承了object才是新式类,但是在Python 3.x中按照如下写法,仍然会被认为是新式类

      class A:
          pass
    • 新式类,类自身或者其父类继承了object则为新式类。 Python 3.x中默认都是新式类,不必显式的继承object

      class A(object):
          pass
    • 经典类解析原则
      从左至右的深度优先遍历,但是如果遍历中出现重复的类,保留第一个
      举例:
    class G:attr = 1
    class P1(G): pass
    class P2(G): attr = 2
    class D(P1,P2): pass
    
    # attr的顺序为[D,P1,G,P2,G]
    
    
    # 因为重复的类只保留第一个,所以最终的解析顺序为[D,P1,G,P2]
    
    print(D.attr)
    • 新式类解析原则
      新式类和经典类一样都是从左至右的深度优先遍历,但是如果遍历中出现重复的类,只保留最后一个
      举例:

      class G1(object): attr = 1
      class G2(object): attr = 3
      class P1(G1,G2): pass
      class P2(G1,G2): attr = 2
      class D(P1,P2): pass
      
      # attr顺序为[D,P1,G1,G2,P2,G1,G2]
      
      
      # 因为重复的类只保留最后一个,所以最终解析顺序为[D,P1,P2,G1,G2]
      
      print(D.attr) # 输出为2 
    • 新式类多重继承容易出错的位置
      如果C继承的两个类P1和P2都继承了相同的类,但是P1和P2的MRO顺序不一样的话,会报错

      • 类的示例图

            (object)
             /   \
            G1   G2
        
        P1(G1,G2) P2(G2,G1)
            \      /
            C(P1,P2)
      • 实例

        class G1(object): attr = 1
        class G2(object): attr = 3
        class P1(G1,G2): pass
        class P2(G2,1): attr = 2
        class D(P1,P2): pass
        
        #P1的MRO顺序为[P1,G1,G2]
        
        
        #P2的MRO顺序为[P2,G2,G1]
        
        print(D.attr) # 输出报错
      • 报错信息:

        Traceback (most recent call last):
          File "mro.py", line 4, in <module>
            class P2(G2,1): attr = 2
        TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
  4. __new__函数和__init__函数
    • __new__函数是实例化类的时候调用的,为__init__函数提供类对象,也就是__init__函数的第一个参数,所以__new__函数必须返回类对象,通常可以用super(A,cls).__new__(cls)获取
    • __init__函数是初始化对象的时候调用的,其中的self参数即是__new__函数返回的。

多态

  • 类具有继承关系,并且子类类型可以向上转型看做父类类型,如果父类中有这种方法,只要传入相应参数就可以使用。
  • 开闭原则

    • 对扩展开放(Open for extension):允许子类重写方法函数
    • 对修改封闭(Closed for modification):不重写,直接继承父类方法函数
  • call函数

    • 作用是把类的实例当作函数进行调用
    • 举例

      class Fib(object):
          def __call__(self,num):
              return num
      
      f = Fib() # 此处f是类的实例
      print f(10) # 此处把类的实例当成函数在用,实际上进行处理的就是__call__函数

动态生成类

  1. 类对象的类型,python中一切都是对象,类也是对象,如果是类,则为type。如果是对象,其类型的类型也还是type

    >>> class MyCls(object):pass
    ... 
    >>> MyCls.__class__
    <class 'type'>
    >>> a=379
    >>> a.__class__
    <class 'int'>
    >>> a.__class__.__class__
    <class 'type'>
    >>> a.__class__.__class__.__class__
    <class 'type'>
  2. type 函数,动态生成类

    type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))

    举例

    >>> class pClass(object):pass
    ... 
    >>> child=type('ChildClass',(pClass,),{})
    >>> child.__name__
    'ChildClass'
    >>> child.__class__
    <class 'type'>
  3. 使用metaclass,生成动态类

    • metaclass 作用
    • metaclass的调用顺序

      类Foo中有metaclass这个属性吗?如果是,Python会在内存中通过metaclass创建一个名字为Foo的类对象(我说的是类对象)。如果没有找到metaclass,会在(父类)中继续寻找metaclass属性,并尝试做和前面同样的操作。如果还是找不到metaclass,Python就会用内置的type来创建这个类对象。

    • metaclass 使用方法

      • 首先自定义metaclass,继承type。
      • 在自定义元类中的__new__函数中返回自定义类,也就是type(class_name,class_parents,class_attr)。
      • 在想使用元类的类定义中设置metaclass属性为目标元类。
    • metaclass实例
      class myMetaClass(type):
          def __new__(metaname, class_name, class_parents, class_attr):
              print("Hello hello")
              return super(myMetaClass,metaname).__new__(metaname, class_name, class_parents, class_attr)
      class Foo(object,metaclass=myMetaClass):
          pass
      
      f = Foo()
      print(type(Foo))

    输出

    Hello hello
    <class '__main__.myMetaClass'>

扩展题

  • ORM是如何实现的(代码在连接,by 廖雪峰)
    • 描述器
    • 动态生成类

猜你喜欢

转载自blog.csdn.net/u013894427/article/details/79154017