动态方法与静态方法、继承、派生类

今日学习内容总结

      在昨日的学习中,我们已经有了面向对象的编程思想。对类和对象有了一定程度的了解。对象,就是数据与功能的结合体,也是一个容器。类就是多个对象中相同数据与功能的结合体。其实也算是对象。在代码中,必须先定义类才能产生对象。今天我们就对面向对象编程做进一步的了解。

动态方法与静态方法

静态方法

      用 @staticmethod 装饰的不带 self 参数的方法叫做静态方法,类的静态方法可以没有参数,可以直接使用类名调用。

  class Student:
      @staticmethod
      def speak(a):
          print(a)
  obj1 = Student()
  # 静态方法就是一个普通的函数,只不过写在类中需要自己传参
  # 类调用静态方法
  Student.speak(123)  # 123
  # 对象调用静态方法
  obj1.speak(321)  # 321

      静态方法是类中的函数,不需要实例。静态方法主要是用来存放逻辑性的代码,主要是一些逻辑属于类,但是和类本身没有交互,即在静态方法中,不会涉及到类中的方法和属性的操作。可以理解为将静态方法存在此类的名称空间中。并且,静态函数可以通过类名以及实例两种方法调用。

动态方法

      动态方法是将类本身作为对象进行操作的方法。他和静态方法的区别在于:不管这个方式是从实例调用还是从类调用,它都用第一个参数把类传递过来。

  class ColorTest(object):
      color = "color"
      @classmethod
      def value(self):
          return self.color

  class Red(ColorTest):
      color = "red"

  class Green(ColorTest):
      color = "green"

  # 类调用绑定给类的方法:会自动将类当做第一个参数传入
  print(ColorTest)  # <class '__main__.ColorTest'>
  g = Green()
  # 这是对象调用绑定给类的方法,不需要传参,会将产生该对象的类自动当做第一个参数传入
  print(g.value())  # green
  print(Green.value())  # green
  

继承

      面向对象编程语言的一个主要功能就是继承。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。

  class Person:
      def __init__(self, name, age, gender):
          self.name = name
          self.age = age
          self.gender = gender
  class Teacher(Person):
      def teach(self):
          print(f'{self.name}老师正在讲课')
  class Student(Person):
      def study(self):
          print(f'{self.name}学生正在学习')

  stu1 = Student('jason', 18, 'male')

  stu1.study()  # jason学生正在学习

      通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”,继承的过程,就是从一般到特殊的过程。在 python 语言中,一个子类可以继承多个基类。在上述代码中,Person 类就是父类,Teacher和Student类就是子类。既然子类继承了父类,那么子类就全部拥有了父类的方法和属性。但是,如果子类里面有一个和父类同样名称的方法,那么就把父类中的同一个方法遮盖住了,显示的是子类自己的方法,这叫做方法的重写。实例化子类Student之后,执行示例方法study(),在继承中基类的构造(init()方法)不会被自动调用,它需要在其派生类的构造中亲自专门调用。在实例化的时候,需要传完整的参数。不然会报错。

查找顺序

      在不继承的情况下名字的查找顺序是先从对象自己的名称空间中查找,没有则去类里面的名称空间查找。

      单继承

  # 名字查找顺序 通过案例查看顺序
  class A:
      def f1(self):
          print('from A.f1')
      def f2(self):
          print('from A.f2')
          self.f1()  
   class MyClass(A):
       def f1(self):
            print('from MyClass.f1')
   obj = MyClass()
   obj.f2()
    # 执行的方法分别是A里面的f2和MyClass里面的f1
  

      由实例可以看出,单继承情况下名字的查找顺序是:先从对象自己的名称空间中查找,没有则去产生对象的类中查找,如果还没有并且类有父类则去父类中查找。

      多继承

      在理解多继承之前,我们可以了解一下python2和python3中多继承情况下的区分。关键在于是否继承了一个默认的object类。

      多继承,就是一个类继承自多个类,它将具有多个类的特征。查找顺序:

      多继承的查找顺序中,有深度优先的情况和广度优先的情况。

      深度优先:父类中名字的查找顺序就是按照继承时从左往右依次查找,如果多个父类还有分类则遵循深度优先。意思是。我们在多继承的情况下查找名字是从左往右一次查找,如果最左边的父类,还有父类。那么查找顺序会继续查找最左边的父类中的父类中有没有这个名字。接下来才会继续按照从左往右的顺序。这就是深度优先。

      广度优先:在深度优先的基础上,如果子类A,继承了B,C,D三个父类,这三个父类又分别继承了E,F,G三个父类,同时E,F,G继承了同一个父类H。在查找的时候,不会查询到H。按照深度优先来查询,最后查询H。这就是广度优先。

派生类

      之前说过继承中无需重新编写原来的类的情况下对这些功能进行扩展:

  class Person:
      def __init__(self,name,age,gender):
          self.name = name
          self.age = age
          self.gender = gender

  class Teacher(Person):
      def __init__(self,name,age,gender,level,salary):
          # 用了Person类里面的__init__方法之后
          # super(Teacher,self).__init__(name,age,gender)  # 子类调用父类的方法 完整语法
          super().__init__(name,age,gender)  # 子类调用父类的方法 精简语法
          # 自己还要添加一个额外的东西
          self.level = level
          self.salary = salary

      这就是无需重新编写原来的类的情况下对这些功能进行扩展的写法,同时我们称这样的子类为派生类。本质上还是子类。可以通过关键字super实现。实现效果:

t1 = Teacher('jason',18,'male','高级',20)

print(t1.__dict__)  # {'name': 'jason', 'age': 18, 'gender': 'male', 'level': '高级', 'salary': 20}
posted @ 2022-04-07 20:56  くうはくの白  阅读(262)  评论(0)    收藏  举报