python面向对象(继承,多态)

本文详细介绍了Python面向对象编程的继承概念,包括单继承、多继承以及如何在子类中调用父类方法。同时阐述了多态的概念和实例,展示了如何利用多态实现不同子类的差异化行为。此外,还讲解了鸭子类型,强调了动态语言中对象类型的灵活判断。最后,讨论了获取对象信息的方法,如`type`、`isinstance`和`dir`函数的使用。
摘要由CSDN通过智能技术生成

python面向对象2

面向对象(继承,多态)

继承

定义
  • 当定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base classSuper class

  • 格式:class 子类名称(基类名称)

class Animal(object):#定义一个名为Animal的基类
    def run(self):
        print('动物可以跑')
        
class Dog(Animal): #定义一个名为Dog的子类
    pass

class Cat(Animal): #定义一个名为Cat的子类
    pass

dogObj = Dog()
catObj = Cat()

dogObj.run()
catObj.run()
       
# 结果
动物可以跑
动物可以跑
  • 对于子类继承的父类的方法,如run,如果子类不做特殊处理,那就会具有和父类的一样的被继承的方法。如果子类对被继承的方法做了修改(函数的定义不变,变的只是函数的实现),那么这就是重写方法
    • 继承的一个好处就是:多态;允许方法重写是多态的具体体现。
子类指定调用父类的方法
  • 在子类的类内,进行指定

    super().父类的方法名()
    父类名字.父类方法(self)
    super(当前类的名字,self).父类的方法名()
    
    class Animal(object):  # 定义一个名为Animal的基类
        def run(self):
            print('动物可以跑')
    
    class Dog(Animal):  
        def run(self):
            return super().run() #子类指定父类中的方法1
    
    
    class Cat(Animal): 
        def run(self):
            return Animal.run(self) #子类指定父类中的方法2
    
    class Fox(Animal):
        def run(self):
            return super(Fox, self).run() #子类指定父类中的方法3
    
    dogObj = Dog()
    catObj = Cat()
    foxObj = Fox()
    
    dogObj.run()
    catObj.run()
    foxObj.run()
    
    # 结果
    动物可以跑
    动物可以跑
    动物可以跑     
    
  • 在子类的类外,无法进行指定

多继承
  • Python同样有限的支持多继承形式
  • 圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,python从左至右搜索 即方法在子类中未找到时,从左到右查找父类中是否包含方法。
  • 格式:class 子类名称(基类1名称, 基类2名称...)
class BaseClass1():
    def fun(self):
        print('这是基类1中的方法')

class BaseClass2():
    def fun(self):
        print('这是基类2中的方法')

class SubClass(BaseClass1, BaseClass2):#继承顺序为BaseClass1, BaseClass2
    pass

subClassObj =SubClass()
subClassObj.fun() #BaseClass1, BaseClass2都有fun()方法,但是SubClass没有进行重写,所以会调用                   #BaseClass1中的fun方法

# 结果
这是基类1中的方法
  • 多继承中指定基类中方法

    父类名字.父类方法(self)
    super(当前类的名字,self).父类的方法名()
    
    class BaseClass1():
        def fun(self):
            print('这是基类1中的方法')
    
    class BaseClass2():
        def fun(self):
            print('这是基类2中的方法')
    
    class SubClass(BaseClass1, BaseClass2):#继承顺序为BaseClass1, BaseClass2
        def fun(self):
            return BaseClass2.fun(self) #进行指定基类中的方法
    
    subClassObj =SubClass()
    subClassObj.fun() #BaseClass1, BaseClass2都有fun()方法,但进行了指定,所以会调用                           #BaseClass2的方法
    
    # 结果
    这是基类2中的方法
    

多态

  • 继承的一个好处就是:多态;允许方法重写是多态的具体体现。
  • 多态的通俗理解:继承自同一父类的不同的子类会重写父类中的某些方法,但他们的方法名是一致的,在调用某些方法时,不同类型的对象会有不同的行为
方法重写
class Animal(object):  # 定义一个名为Animal的基类
    def run(self):
        print('动物可以跑')

class Dog(Animal):
    def run(self):
       print('这是狗在跑')


class Cat(Animal):
    def run(self):
        print('这是猫在跑')

class Fox(Animal):
    def run(self):
        print('这是猫在跑')

dogObj = Dog()
catObj = Cat()

dogObj.run()
catObj.run()

# 结果
这是狗在跑
这是猫在跑
进一步理解
  • 对于一个变量,我们只需要知道它是Animal类型,无需确切地知道它的子类型,就可以放心地调用run()方法,而具体调用的run()方法是作用在AnimalDogCat还是Tortoise对象上,由运行时该对象的确切类型决定
  • 调用方只管调用,不管细节;而当我们新增一种Animal的子类时,只要确保run()方法编写正确,不用管原来的代码是如何调用的。这就是著名的“开闭”原则:
    • 对扩展开放:允许新增Animal子类;
    • 对修改封闭:不需要修改依赖Animal类型的run_twice()等函数

鸭子类型

  • 对于静态语言(例如Java)来说,如果需要传入Animal类型,则传入的对象必须是Animal类型或者它的子类,否则,将无法调用run()方法。因为会做类型检查,类型不符,则会抛异常。
  • 对于Python这样的动态语言来说,则不一定需要传入Animal类型。我们只需要保证传入的对象有一个run()方法就可以了
含义
  • 只要传入的对象就行

  • “file-like object“,“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子

class Animal(object):  # 定义一个名为Animal的基类
    def run(self):
        print('动物可以跑')

def run_twice(Animal):
    Animal.run()
    Animal.run()

class MyClass():
    def run(self):
        print('这不是一个Animal的run,这是MyClass中的run')

myclassObj = MyClass()
run_twice(myclassObj) #myclassObj就像只鸭子,它有run_twice参数中Animal的run方法,那么就运行                       #Myclass中的run方法
                      #至于run_twice运行的是不是Animal的run不管,只要传入的参数有run方法就行

# 结果
这不是一个Animal的run,这是MyClass中的run
这不是一个Animal的run,这是MyClass中的run    

获取对象信息(type,isinstance,dir)

type
  • 判断基本数据类型
print(type('a'))

# 结果
<class 'str'>
  • 使用types模块

    import types
    
    def fun():
        pass
    
    print(type(fun) == types.FunctionType)
    print(types.FunctionType)
    
    
    # 结果
    True
    <class 'function'>
    
isinstance
  • 格式:isinstance(变量,类型名),返回值是布尔型

    print(isinstance(1, int))
    print(isinstance(1, str))
    
    # 结果
    True
    False
    
    • 总是优先使用isinstance()判断类型
dir
  • 如果要获得一个对象的所有属性和方法,可以使用dir()函数,它返回一个包含字符串的list

    print(dir('a'))
    
    # 结果
    ['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__',
     
     'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
    
    • 通过内置的一系列函数,我们可以对任意一个Python对象进行剖析,拿到其内部的数据。要注意的是,只有在不知道对象信息的时候,我们才会去获取对象信息。

    • 举例

      def readImage(fp):
          if hasattr(fp, 'read'):
              return readData(fp)
          return None
      
      • 假设我们希望从文件流fp中读取图像,我们首先要判断该fp对象是否存在read方法,如果存在,则该对象是一个流,如果不存在,则无法读取。hasattr()就派上了用场
      • 根据鸭子类型,有read()方法,不代表该fp对象就是一个文件流,它也可能是网络流,也可能是内存中的一个字节流,但只要read()方法返回的是有效的图像数据,就不影响读取图像的功能

参考链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值