面向对象


面向对象(Object Oriented Programming,OOP,面向对象程序设计)

  • 面向对象是一种编程方式,需要使用 "类" 和 “对象” 实现,也就是说面向对象就是“类”和“对象”的使用

  • 类:

    • 创建类

      class Foo(object): #创建类,类名称的首字母必须是大写,括号里面是类的基类
          def func(self): #创建类中的函数时(self)是特殊参数,必须要写
              print("hello world")  #函数的表达式
      obj=Foo() #创建类Foo()的对象obj,对类Foo进行实例化
      obj.func()  #用对象调用类Foo中的函数
      • 类就是一个模板,这个模块可以包含多个函数
      • 对象就是根据模板创建的实例,通过实例对象可以执行类中的函数
      • 类定义使用的关键字是class
      • 类名称的首字母必须是大写
      • 所有类的基祖都是pbject,所以创建类的时候都是需要继承的
      • 面向对象的三大特性:(封装,继承,多态)
    • 初始化类(构造类)(一个类,不管是否写构造方法,它都是有构造方法的

      • 在定义类时,可以为类添加一个特殊的__init__()方法,当创建实例时,__init__()方法被自动调用

        class Person(object):
        
            def __init__(self,name,age,gender):
                self.name=name   #每一个人都有自己的名字
                self.age=age   #每一个人都有自己的年龄
                self.gender=gender   #每一个人都有自己的性别

         Ps:__init__() 方法的第一个参数必须是 self

      • 类的实例化

        obj=Person(name="tang",age=21,gender="male")   #类的实例化
      • 对象引用

        obj=Person(name="tang",age=21,gender="male")   #类的实例化
        print(obj.name)
        print(obj.age)
        print(obj.gender)
  • 类的方法(“方法”就是封装在类里的一种特殊的函数)

    • 普通/实例方法(也就是之前学的函数)

      class Person(object):
          def __init__(self,name,age,gender):
              self.name=name   #每一个人都有自己的名字
              self.age=age   #每一个人都有自己的年龄
              self.gender=gender   #每一个人都有自己的性别
          def show(self):   #封装一个查看Person属性的函数
              print(f"name:{self.name},age:{self.age},gender:{self.gender}")   #函数的表达式和格式化输出
      
      obj=Person(name="tang",age=21,gender="male")   #把类Person实例化为obj
      obj.show()   #调用方法

       类内部定义的函数,调用的方法和就是函数的调用方法,输出结果:

      name:tang,age:21,gender:male
    • 特性方法(可以理解为只读属性,不具有写的属性)

      class Person(object):
          def __init__(self,name,age,gender):
              self.name=name   #每一个人都有自己的名字
              self.age=age   #每一个人都有自己的年龄
              self.gender=gender   #每一个人都有自己的性别
      
          @property  # 装饰器
          def getNameAge(self):
              return f"name:{self.name},age:{self.age}"
      obj=Person(name="tang",age=21,gender="male")   #把类Person实例化为obj
      print(obj.getNameAge)   #调用方法

      类内部定义的以@staticmethod装饰的函数,类方法的调用关系可以通过print后的表述得知,输出结果

      name:tang,age:21

      当一个方法我们只想获取它的值并且这个方法里面不需要形式参数的时候,那么这个方法我们可以定义成特性方法

    • 静态方法(用类名来调用)

      class Person(object):
          def __init__(self,name,age,gender):
              self.name=name   #每一个人都有自己的名字
              self.age=age   #每一个人都有自己的年龄
              self.gender=gender   #每一个人都有自己的性别

      @staticmethod #装饰器 def info(city): return city print(Person.info("xian"))

      输出结果

      xian
    • 类方法

      class Person(object):
          def __init__(self,name,age,gender):
              self.name=name   #每一个人都有自己的名字
              self.age=age   #每一个人都有自己的年龄
              self.gender=gender   #每一个人都有自己的性别
          @classmethod  # 类方法只能使用类名来调用
          def per(cls):
              return "hello world"
      print(Person.per())

      输出结果:

      hello world
  • 类的属性(实例属性和数据【类】属性)

    class Person(object):
        city="xian" #数据属性
    
        def __init__(self,name,age,gender):
            self.name=name   #实例属性
            self.age=age   #实例属性
            self.gender=gender   #实例属性
    • 输出实例(类)属性

      class Person(object):
          country="chian"   #数据属性
      
          def __init__(self,name,age,gender):
              self.name=name   #每一个人都有自己的名字
              self.age=age   #每一个人都有自己的年龄
              self.gender=gender   #每一个人都有自己的性别
      
      print(Person.country)

       输出结果:

      chian
    • 输出数据属性

      class Person(object):
          country="chian"   #数据属性
      
          def __init__(self,name,age,gender):
              self.name=name   #每一个人都有自己的名字
              self.age=age   #每一个人都有自己的年龄
              self.gender=gender   #每一个人都有自己的性别
      
          def getName(self):
              return self.name
          def getAge(self):
              return self.age
          def getGender(self):
              return self.gender
      obj=Person("tang",21,"male")
      print(obj.getName())
      print(obj.getAge())
      print(obj.getGender())

       输出结果:

      tang
      21
      male
    • 修改实例属性

      class Person(object):
          country="chian"   #数据属性
      
          def __init__(self,name,age,gender):
              self.name=name   #每一个人都有自己的名字
              self.age=age   #每一个人都有自己的年龄
              self.gender=gender   #每一个人都有自己的性别
      
          def setName(self,name):
              self.name=name
      
          def geyName(self):
              return self.name
      
      obj=Person(name="tang",age=21,gender="male")
      print("更改之前的实例属性:",obj.geyName())   #查看更改之前的实例属性
      obj.setName(name="wang")   #更改实例属性
      print("更改之后的实例属性:",obj.geyName())   #查看更改之后的实例属性

      输出结果:

      更改之前的实例属性: tang
      更改之后的实例属性: wang
  • 类的继承

    • Java类继承和Python类继承的区别:Java是单继承,Python是多继承(可以继承多个类)

    • 类的继承会继承被继承类的方法跟属性

      class A(object):
          def __init__(self,name):
              self.name=name
          def show(self):
              print(f"name:{self.name}")
      class B(A):
          def __init__(self,name):
              A.__init__(self,name) #继承类A的属性
      
      obj=B(name="tang")
      obj.show() #类B中本来是没有这个方法的,但是它继承了A类,所以可以直接调用A类中的方法

      输出结果:

      name:tang
    • 方法重写:子类和父类的方法名称一致,父类的方法没法满足子类时使用

      class A(object):
          def __init__(self,name):
              self.name=name
      
          def show(self):
              print(f"name:{self.name}")
      
      class B(A):
          def __init__(self,name,age):
              self.age=age
              A.__init__(self,name) #继承类A的属性
      
          def show(self):
              print(f"name:{self.name},age:{self.age}")
      
      obj=B(name="tang",age=21)
      obj.show()

      如果我们调用A类的方法,只会输出B类继承A类的属性,不会输出B类自带的属性,这个方法没法满足B类使用,所以我们要在B类中重新写一个方法,输出结果:

      name:tang,age:21
    • 多类继承(多类继承和单类继承一样,会继承父类的属性跟方法)

      class A(object):
          def __init__(self,name):
              self.name=name
      
          def func(self):
              print(f"name:{self.name}")
      
      class B(object):
          def __init__(self,age):
              self.age=age
      
          def show(self):
              print(f"age:{self.age}")
      
      class C(B,A):
          def __init__(self,name,age,gender):
              A.__init__(self,name)#注意标点符号
              B.__init__(self,age)#注意标点符号
              self.gender=gender
      
      
      obj=C(name="tang",age=21,gender="male")
      obj.func()
      obj.show()

      输出结果:

      name:tang
      age:21

      同样方法重写在多继承中也可以使用:

      class A(object):
          def __init__(self,name):
              self.name=name
      
          def show(self):
              print(f"name:{self.name}")
      
      class B(object):
          def __init__(self,age):
              self.age=age
      
          def show(self):
              print(f"age:{self.age}")
      
      class C(B,A):
          def __init__(self,name,age,gender):
              A.__init__(self,name)#注意标点符号
              B.__init__(self,age)#注意标点符号
              self.gender=gender
          def show(self):
              print(f"name:{self.name},age:{self.age},gender:{self.gender}")
      
      obj=C(name="tang",age=21,gender="male")
      obj.show()

      输出结果:

      name:tang,age:21,gender:male
    • 类继承中调用方法的顺序

      • mro()方法解析顺序

      • 从下到上:类继承调用方法,首先是在子类中查找,有的话会直接使用,没有的话会调用父类中的方法,主要体现在单类继承中

        class A(object):
            def __init__(self,name):
                self.name=name
            def show(self):
                print(f"name:{self.name}")
        
        class B(A):
            def __init__(self,name,age):
                self.age=age
                A.__init__(self,name)
        
        obj=B(name="tang",age=21)
        obj.show()
        print(B.mro())

        输出结果:

        name:tang
        [<class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
      • 从左到右:类继承调用方法,首先是在子类中查找,有的话会直接使用,没有的话会调用父类中的方法,父类调用的方法是从左到右,主要体现在多类继承中

        class A(object):
            def __init__(self,name):
                self.name=name
        
            def show(self):
                print(f"name:{self.name}")
        
        class B(object):
            def __init__(self,age):
                self.age=age
        
        class C(B,A):
            def __init__(self,name,age,gender):
                A.__init__(self,name)#注意标点符号
                B.__init__(self,age)#注意标点符号
                self.gender=gender
        
        obj=C(name="tang",age=21,gender="male")
        obj.show()
        print(C.mro())

        输出结果:

        name:tang
        [<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
  • 鸭子类型:在程序设计中,鸭子类型(英语:duck typing)是动态类型的一种风格。

    • 鸭子测试”可以这样表述:

      “当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”
    • 案例:

      class Duck():
          def walk(self):
              print("I walk like a duck")
          def swim(self):
              print('I swim like a duck')
      
      class Person():
          def walk(self):
              print("I walk like a duck")
          def swim(self):
              print('I swim like a duck')
      
      def func(duck):  # 是Duck类的对象
          duck.walk()
      person=Person()
      func(duck=Person())
      func(duck=Duck())

      可以看出Pseron类拥有和Duck类一样的方法,当程序调用Duck类,并利用了其中的walk和swim方法时,我们传入Person类也一样可以运行,程序并不会检查类型是不是Duck,只要他拥有 walk()和swim()方法,就能被正确地调用。输出结果:

      I walk like a duck
      I walk like a duck