python学习笔记-OOP

#===========================类的成员检查===================================
#对象所有成员检查
    obj.__dict__ # dict前后各有两个下划线
#类所有的成员
  class_name.__dict__ # dict前后各有两个下划线
  
#=========================类和对象的成员分析=============================
#创建对象的时候,类中的成员不会放入对象当中,而是得到一个空对象,没有成员  
#对象访问一个成员时,如果对象中没有该成员,尝试访问类中的同名成员, 
#如果对象中有此成员,一定使用对象中的成员
#=============================self============================
#self在对象的方法中表示当前对象本身,如果通过对象调用一个方法,那么该对象会自动传入到当前方法的第一个参数中
#self并不是关键字,只是一个用于接受对象的普通参数,理论上可以用任何一个普通变量名代替
#方法中有self形参的方法成为非绑定类的方法,可以通过对象访问, 没有self的是绑定类的方法,只能通过类访问
#使用类访问绑定类的方法时, 如果类方法中需要访问当前类的成员,可以通过__class__成员名来访问
  Class A():
      a = 1
      def b(s): #非绑定类的方法,self不是关键字,可以用普通参数代替
          s.a = 2
      def c(): #绑定类的方法
        __class__.a = 2 #绑定类的方法访问当前类的成员
  a = A()
  a.b() #系统会默认把a作为第一个参数传入函数
  A.c() #绑定类的方法,只能通过类访问
  A.b(a) #self被a替换,也允许运行A.b(A)不会报错。
  
#=============================封装============================
# private #私有的,Python的私有不是真私有,是一种name mangling的改名策略,可以使用__dict__查看真正的属性
# private 在成员前面添加"__"表示
# private成员 只能在当前类或对象中访问

# protected #受保护的,也是使用了name mangling的改名策略
# protected 在成员前面添加"_"表示
# protected成员 在类中或者子类中都可以进行访问,但是在外部不可以

# public #公开的,公共的

    class Person():
        name = "a" #共有成员
        _petname = "b" #受保护的成员
        __age = 11    #私有成员
    a = Person()
    a.name
    a._petname #能调用,但不能被外部import导入
    #a.__age #无法调用

#=============================继承============================
# 子类继承父类后并没有将父类成员完全赋值到子类中,而是通过引用关系访问调用
# 子类一旦继承父类,则可以使用父类中除私有成员外的所有内容
    class A(B): #A是B的子类、派生类,B是A的父类、基类、超类    
      a = super().b() #调用super().父类的成员来调用
      a = B.b(self) #也可以使用父类名.父类成员来调用

# 构造函数使用__init__表示
# 在对象进行实例化的时候,系统自动调用的一个函数叫构造函数,通常此函数用来对实例对象进行初始化
    class A():
        def __init__(self,a):  #一定有至少一个变量(self)
    class B(A):
        #A.__init__(self, "111") #方法1,调用父类构造函数
        #super(A, self).__init__("111") #方法2,调用父类构造函数
        pass
    #b = B() #无法调用
    b = B(c) #子类没定义构造函数,自动查找父类构造函数;参数应该按父类参数构造
    
# super不是关键字,而是一个类
# 作用是MR0(MethodResolustionOrder)列表中的第一个类,可以使用__mro__查看继承顺序的列表
# super于父类直接没任何实质性关系,但通过super可以调用到父类

# 单继承和多继承,实际使用中不推荐使用多继承
# 菱形继承/钻石继承问题
# 多个子类继承自同一个父类,这些子类由被同一个类继承,于是继承关系图形成一个菱形图谱
# MRO就是多继承中,用于保存继承顺序的一个列表
#   python本身采用C3算法来多多继承的菱形继承进行计算的结果
#   MRO列表的计算原则:
#     1、子类永远在父类前面
#     2、如果多个父类,则根据继承语法中括号内类的书写顺序存放
#     3、如果多个类继承了同一个父类,孙子类中只会选取继承语法括号中第一个父类的父类

# Mixin,是一种类的多继承的机制,为了解决多重继承的问题
# Mixin是一种思想,用部分实现的接口来实现代码复用。可以用来解决多继承的问题,又可以用来扩展功能。
#  职责必须单一,如果由多个功能,则写多个Mixin
    - Mixin不能依赖于子类的实现
    - 子类即使没有继承这个Mixin类, 也能照样工作,只是缺少了某个功能
# 优点
    - 使用Mixin可以在不对类进行任何修改的情况下,扩充功能
    - 可以方便的组织和维护不同功能组件的划分
    - 可以根据需要任意调整功能类的组合
    - 可以避免创建很多新的类,导致类的继承混乱

#=============================多态============================
# 多态性:多态性是指具有不同功能的函数可以使用相同的函数名;多态性依赖于:继承 
    def func(obj):
        print(obj.__len__())
    func("aaa");func([1,2,3]) #多态性,一个函数名调用不同内容的函数;
    
# 多态:一类事物有多种形态;多态依赖于:抽象

#=============================类相关函数============================
    issubclass(A,B) #检测一个类是否是另一个类的子类
    isinstance(b,B) #检测一个对象是否是一个类的实例
    hasattr(a,name) #检测一个对象是否由成员xxx
    getattr #get attribute
    setattr #set attribute
    delattr #delete attribute
    dir(A) #获取对象的成员列表
    
#=============================类的成员描述符(属性)============================
# 类的成员描述符是为了在类中对类的成员属性进行相关操作而创建的一种方式
    class A():
        def __init__(self):
            self.name = "NoName"
    a = A()
    # 属性的三种用法
    a.name = "Mars" # 1, 赋值
    print(a.name) # 2. 读取
    del a.name # 3. 删除

# 如果想增加一些附加的操作,大概有三种方法
  1 使用类的方式:适合多个类中的多个属性共用用一个描述符
  2 使用属性修饰符:在当前类中使用,控制一个类中的一个属性
  3 使用property函数:在当前类中使用,可以控制一个类中多个属性,
# property的四个参数顺序是固定的,第一个参数代表读取,第二个代表写入,第三个代表删除时调用的函数
    property(fget, fset, fdel, doc) 
        
    class Person():
    # 函数的名称可以任意
    def fget(self):
        return self._name * 2
    def fset(self, name):
        self._name = name.upper() # 所有输入的姓名以大写形式保存
    def fdel(self):
        self._name = "NoName"
    name = property(fget, fset, fdel, "这是描述")

    
#=============================类的内置属性============================
  __dict__:以字典的方式显示类的成员组成
  __doc__: 获取类的文档信息
  __name__:获取类的名称,如果在模块中使用,获取模块的名称
  __bases__: 获取某个类的所有父类,以元组的方式显示
  
#=============================类的常用魔术方法============================
# 魔术方法就是不需要人为调用的方法,基本是在特定的时刻自动触发
# 魔术方法的统一的特征,方法名被前后各两个下滑线包裹
# 操作类
    __init__ # 构造函数
    __new__ #对象实例化方法,此函数较特殊,一般不需要使用,在init之前调用
    __call__ #对象当函数使用的时候触发
    __str__ #当对象被当做字符串使用的时候调用
    __repr__ #返回字符串
# __repr__与__str__具体区别:
    #print操作会首先尝试__str__和str内置函数(print运行的内部等价形式),它通常应该返回一个友好的显示。
    #__repr__用于所有其他的环境中:用于交互模式下提示回应以及repr函数,如果没有使用__str__,会使用print和str。
    #__repr__通常应该返回一个编码字符串,可以用来重新创建对象,或者给开发者详细的显示。

# 描述符相关
    __set__
    __get__
    __delete__

# 属性操作相关
    __getattr__: 访问一个不存在的属性时触发
    __setattr__: 对成员属性进行设置的时候触发,作用:进行属性设置的时候进行验证或者修改
    #注意: 在__setattr__方法中不能对属性直接进行赋值操作,否则死循环
    
    class A():
            a = 0
        def __init__(self, a = 0):
            pass
        def __call__(self):
            pass
        def __str__(self):
            pass 
        def __getattr__(self, a):
                pass
        def __setattr__(self, a, value):
        print("设置属性: {0}".format(a))
        #self.name = value # 该语句会导致死循环,报错
        super().__setattr__(name, value) # 此种情况,为了避免死循环,规定统一调用父类魔法函数
        
    a1 = A() # 调用__new__和__init__
    a() # 调用__call__
    print(a1) # 调用__str__
    print(a1.a)  # 调用__getattr__
    a1.a = 1 # 调用__setattr__

# 运算分类相关魔术方法
    __gt__: 进行大于判断的时候触发的函数;
    
    class Student():
        def __init__(self, name):
            self._name = name
        def __gt__(self, obj):
            print("哈哈, {0} 会比 {1} 大吗?".format(self, obj))
            return self._name > obj._name
    print(Student("one") > Student("two")) #调用__gt__
    
#=============================类和对象的三种方法============================
# 三种方法的案例
    class Person:
    # 实例方法
    def eat(self):
            pass

    # 类方法
    # 类方法的第一个参数,一般命名为cls,区别于self
    @classmethod
    def play(cls):
            pass
        
    # 静态方法
    # 不需要用第一个参数表示自身或者类
    @staticmethod
    def say():
            pass
    yueyue = Person()
    # 实例方法
    yueyue.eat()
    # 类方法
    Person.play()
    yueyue.play()
    #静态方法
    Person.say()
    yueyue.say()
    
#=============================抽象类============================
# 抽象方法:没有具体实现内容的方法成为抽象方法
# 抽象类的使用需要借助abc模块
# 抽象类的使用
    - 抽象类可以包含抽象方法,也可以包含具体方法
    - 抽象类中可以有方法也可以有属性
    - 抽象类不允许直接实例化
    - 必须继承才可以使用,且继承的子类必须实现所有继承来的抽象方法
    - 假定子类没有是现实所有继承的抽象方法,则子类也不能实例化
    
    import abc
    #声明一个类并且指定当前类的元类
    class Human(metaclass=abc.ABCMeta):
        # 定义一个属性
        a = 1
    # 定义一个抽象的方法
    @abc.abstractmethod
    def smoking(self):
        pass
    # 定义类抽象方法
    @abc.abstractclassmethod
    def drink():
        pass
    # 定义静态抽象方法
    @abc.abstractstaticmethod
    def play():
        pass
    # 定义具体方法
    def sleep(self):
        pass
        
#============================自定义类============================
#类是一个类定义和各种方法的自由组合
# 1、借助于MethodType实现
# 2、借助于type实现
# 3、借助于元类实现- MetaClass
# 自定义类例1:
    class A():
      pass
    def say(self):
      pass
    say1 = say # 补充:函数名可以当变量使用
    A.say = say # 可以定义类和函数,然后自己通过类直接赋值。

# 自定义类例2:借助于MethodType实现
    from types import MethodType
    class A():
      pass
    def say(self):
      pass
    a = A()
    a.say = MethodType(say, A)

# 自定义类例3:借助于type实现
    # 先定义类应该具有的成员函数
    def say(self):
      pass
    def talk(self):
      pass
    #用type来创建一个类
    A = type("AName", (object, ), {"class_say":say, "class_talk":talk})
    a = A() 
    a.class_say()
    a.class_talk()

# 自定义类例3:借助于元类实现- MetaClass
# 元类写法是固定的,必须继承自type
# 元类一般命名以MetaClass结尾
    class AMetaClass(type):
        # 注意以下写法
        def __new__(cls, name, bases, attrs):
            #业务处理
            print("元类")
            attrs['id'] = '000000'
            return type.__new__(cls, name, bases, attrs)
    # 元类定义完就可以使用,使用注意写法
    class B(object, metaclass=AMetaClass):
        pass
    b = B()
    print(b.id)

猜你喜欢

转载自blog.csdn.net/maopc1987/article/details/85232119