• 面向对象编程(oop)


    类和面向对象(oop)

    概述

    • oop思想
      任意一个任务,首先想到的是任务的构成和实现过程。

    • 类和对象的概念

      • 类:抽象名词,代表一个集合,代表一类事物。
      • 对象:具象的事物,单个个体。
    • 类的内容

      • 属性(变量):表明事物特征
      • 方法(函数):表明事物功能
    • 类的命名

      • 大驼峰比较规范。
      • 必须用class关键字。
      • 由属性和方法组成,其他不许出现。
      • 成员属性定义可直接用变量赋值,如果没有值需使用None。
    • 访问类和对象的成员

      # 对象成员检查
      obj.__dict__
      # 类成员检查
      class_name.__dict__  
      
    • 实例

       # 定义一个简单的类
       class StudentPython():
       name = None
       age = 18
       def Studentplay(self):
           print("learning python")
      
       # David为对象,此时实例化类
       David = StudentPython()
       print(David.name)
       print(David.age)
       David.Studentplay()
      

    类和对象的成员分析

    • 类和对象都可以储存成员,成员可以归类所有也可以归对象所有。

    • 创建对象时,类中的成员不会放入对象中,而是得到一个空对象。

    • 通过对象对类中成员重新赋值或者通过对象添加成员时,对应成员会保存在对象中,而不会修改类成员。

    • 实例

      class Teacher():
          name = "aaa"
          age = 28
          def TeacherSay(self):
              self.name = "Mary"
              self.age = 20
              print("My name is {0}".format(self.name))
              print("My age is {0}".format(self.age))
        
      t = Teacher()
      print(t.name)  
      print(t.age)
      t.TeacherSay()
      
      '''
      aaa
      28
      My name is Mary
      My age is 20
      '''
      

    关于self

    • self在对象的方法中表示当前对象本身,如果通过对象调用方法,那么该对象会自动传入到当前方法的第一个参数中。

    • self并不是关键字,理论上可以用任何一个普通变量名代替。

    • 方法中有self形参的称为非绑定类的方法,可以通过对象访问,没有self的称为绑定类方法,只能通过类访问。

    • 实例

      class Teacher():
          name = "aaa"
          age = 28
          def TeacherSay(self):
              self.name = "Mary"
              self.age = 20
              print("My name is {0}".format(self.name))
              print("My age is {0}".format(self.age))
          def TeacherSayAgain():
              print(__class__.name)
              print(__class__.age)
              print("learning python")
      
      t = Teacher()
      t.TeacherSay()
      # 调用绑定类方法通过类访问
      Teacher.TeacherSayAgain()
      
      '''
      My name is Mary
      My age is 20
      aaa
      28
      learning python
      '''
      

    面向对象的三大特性

    封装,继承,多态

    • 封装
      • 三个级别:公开(public),受保护(protected),私有(private)。

      • 判别对象的位置:对象内部,对象外部,子类中。

      • 私有:私有成员是最高级别的封装,只能在当前类或对象中访问,外部不能访问。python的私有不是真私有,是一种为name mangling的改名策略。

        class Person():
            # name为共有成员
            name = "David"
            #__age为私有成员
            __age = 18
        
      • 受保护:将对象成员进行一定级别的封装,在父类和子类中可以访问,外部不能访问。

      • 公开:对对象成员没有任何操作,任何地方都可以访问。

    • 继承
      • 继承就是一个类可以获得另外一个类中的成员属性和方法。

      • 被继承的为父类(基类或超类),用于继承的类为子类(派生类)。

      • 所有的类都继承自object类,即所有的类都是object类的子类。

      • 子类继承父类后并没有将父类成员完全赋值到子类,而是通过引用关系访问调用。

      • 子类一旦继承父类,可以使用父类中除私有成员外的所有成员属性和方法,子类还可以定义独有的成员属性和方法。

      • 子类中定义的成员如果和父类成员相同,则优先使用子类成员。

      • 如果想在子类中扩充父类方法,可以在定义新方法时访问父类成员来进行代码重用,可以父类名.父类方法也可以super().父类方法的格式调用。
        super不是关键字,而是一个类。super的作用是获取MRO(MethodResolutionOrder)列表中的第一个类

        class Person():
            name = "None"
            __age = 18
            _score = 0
            def Study(self):
                print("learning python")
        
        class Student(Person):
            def HaveTest(self):
                print("have to take exam")
            # 扩充父类函数,方法一二
            def Study(self):
                Person.Study(self)# 注意这里有self
                self.HaveTest()
                '''
                super().Study()# 注意这里没有self
                # super(Student, self).Study()也可以
                self.HaveTest()
                '''    
                               
        David = Student()
        print(David.name)
        David.Study()
        
        '''
        None
        learning python
        have to take exam
        '''
        
      • 继承中的查找顺序:子类优先查找自己的变量,没有则查找父类变量;
        子类中如果构造函数没有定义,则按照MRO顺序查找调用父类的构造函数,子类有定义则不继续向上查找。
        构造函数:每次实例化第一个被自动调用的函数

      • 单继承和多继承:单继承每个类只能继承一个类,多继承每个类能继承多个类;单继承逻辑清晰语法简单但功能不能受限,多继承扩展方便但关系混乱且会出现菱形继承(钻石继承)问题。

      • MRO:是在多继承中用于保存继承顺序的一个列表;
        MRO计算原则:子类永远在父类前;如果多个父类则根据括号内类的书写顺序存放;如果多个类继承了同一个父类,孙子类中只会选取括号内第一个父类的父类。

    • 多态
      • 多态就是同一个对象在不同情况下有不同状态出现。

      • Mixin设计模式:主要采用多继承方式对类功能进行扩展。首先必须表示某一单一功能,如果有多个功能则写多个Mixin,当子类没有继承某一Mixin类也能照常工作。

        class Person():
            def __init__(self, name, age):
                self.name = name
                self.age = age
            def Play(self):
                print("have fun")
            def Sleep(self):
                print("sleeping...")
        # 创建一个Mixin
        class TeacherMixin():
            def Work(self):
                print("teaching somebody")
        
        class StudentMixin():
            def Study(self):
                print("learning python")
        
        class Student(Person, StudentMixin):
            pass
        class Teacher(Person):
            def __init__(self):
                self.name = "Alex"
        
        David = Student("David", 18)
        print("my name is {0}, my age is {1}".format(David.name, David.age))
        David.Study()
        David.Play()
        print("*" * 20)
        Alex = Teacher()
        print("my name is {0}".format(Alex.name))
        Alex.Sleep()
        
        '''
        my name is David, my age is 18
        learning python
        have fun
        ********************
        my name is Alex
        sleeping...
        '''
        

    类相关函数

    • issubclass:检测一个类是否是另一个类的子类。
    • isinstance:检测一个对象是否是一个类的实例。
    • hasattr:检测一个对象是否有成员xxx。
    • dir:获取对象的成员列表

    类的成员描述符(属性)

    • 类的成员描述符是为了在类中对类的成员属性进行相关操作

    • 三种方式:使用类实现描述器;使用属性修饰符;使用property函数property(fget, fset, fdel, doc)

      class Person():
          '''
          property函数实例
          定义一个Person类,具有name,age属性,
          对于任意输入的name都希望以大写字母保存
          '''
          def fget(self):
              # 返回操作后的属性
              return self._name
          def fset(self, name):
              # 传入需要操作的属性
              self._name = name.upper()
          def fdel(self):
              self._name = "NoName"
          name = property(fget, fset, fdel, "None")
          age = 18
        
      David = Person()
      David.name = "David"
      print("my name is {0}".format(David.name))
      '''
      my name is DAVID
      '''
      

    类的内置属性

    __dict__:以字典的方式显示类成员的组成
    __doc__:获取类的文档信息
    __name__:获取类的名称,如果在模块中使用则获取模块名称
    __bases__:以元组方式显示类的所有父类

    类的常用魔术方法

    • 魔术方法就是不需要认为调用,在特定的情况下自动触发的方法,统一特征是方法名被前后两个下划线包裹。
      __init__:构造函数
      __new__:对象实例化方法
      __call__:对象当函数时使用
      __str__:对象被当作字符串时使用
      __repr__:返回字符串
      __getattr__:访问一个不存在的属性时触发,此时不会报错
      __gt__:进行大于判断的时候触发
      __setattr__:对成员属性设置的时候触发

      # __setattr__示例
      class A():
          def __setattr__(self, name, value):
              print("设置属性{0}为{1}".format(name, value))
              '''
              这样会导致死循环
              self.name = value
              '''
              # 为了避免这种情况,使用父类魔法函数
              super().__setattr__(name, value)
      a = A()
      a.age = 18       
      

    类和对象的三种方法

    • 实例方法:必须要创建实例对象才能调用,第一个参数必须是实例对象,该参数名一般约定为self,如果方法里面有初始化函数也必须对初始化函数进行传参。且只能由实例对象调用

    • 类方法:使用装饰器@classmethod,第一个参数必须是当前类对象,该参数名一般约定为cls,可以由实例对象和类对象调用。

    • 静态方法:使用装饰器@staticmethod,没有self和cls参数,可以由实例对象和类对象调用。
      参考博客Python 实例方法、类方法、静态方法的区别与作用

      class Person():
          def Work(self):
              print("have to work")
          @classmethod
          def Study(cls):
              print("have to study")
          @staticmethod
          def Sleep():
              print("sleeping...")
      # 实例方法
      p = Person()
      p.Work()
      #Person.Work()会报错
      # 类方法
      p.Study()
      Person.Study()
      # 静态方法
      p.Sleep()
      Person.Sleep()
  • 相关阅读:
    [20211108]索引分裂块清除日志增加(唯一索引)2.txt
    [20220104]in list 几种写法性能测试.txt
    [20211215]提示precompute_subquery补充.txt
    [20211217]滑稽可笑的程序代码2.txt
    SourceTree通过配置SSH来链接GitLab
    Docker在虚拟机中的安装
    .Net 6 Log4Net【.Net Core】
    es(elasticsearch)磁盘清理记录
    JSON 之 Jackson
    git FAQ
  • 原文地址:https://www.cnblogs.com/geqianLee/p/12346309.html
Copyright © 2020-2023  润新知