面向对象(终极篇 )

1. 继承简介

  • 继承是面向对象的三大特性之一
  • 在定义类 时 我们可以在类的 括号里面指定 当前的父类
  • 继承的特性:
    • 继承提高了代码的复用性
    • 继承使类与类之间产生了关系。 有了关系,才有了多态的特性

2. 方法重写

  • 如果子类和父类有同名的方法。则通过子类实例去调用方法时,会调用子类的方法,而不是父类的方法,此过程我们称之为方法的重写(覆盖)
  • 当我们调用一个对象时:
  • 会优先去当前对象的父类中寻找,如果有,则调用。
  • 如果没有,则会去父类的父类中寻找,如果有,则调用
  • 如果没有,以此类推,直到找到 object 如果依然没有找到就会直接报错
class A():

    def test(self):
        print('A......')

class B(A):

    def test(self):
        print('B......')


class C(B):

    def test(self):

        print('C......')

    def text(self):

        print('text....')
        
a = C()
a.test()
a.text()

b = B()
b.test()


在这里插入图片描述

3. super()

  • super()可以直接获取当前类的父类
  • 并且通过super()返回对象调用父类方法时,不需要传递self

父类中的所有方法都会被子类继承,包括特殊方法,否则就会报错

class Animal():
    def __init__(self, name):

        self._name = name

    def run(self):
        print('动物跑....')

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name):
        self._name = name

    def sleep(self):
        print('动物睡觉....')


class Dog(Animal):

    def speak(self):
        print('汪汪....')


d = Dog() # TypeError: __init__() missing 1 required positional argument: 'name'

所以我们将父类的特殊方法传进来,但是子类的特殊方法会将父类的特殊方法给覆盖掉

class Animal():
    def __init__(self, name):

        self._name = name

    def run(self):
        print('动物跑....')

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name):
        self._name = name

    def sleep(self):
        print('动物睡觉....')


class Dog(Animal):

    def __init__(self, name, age):
        self._name = name
        self._age = age
    @property
    def age(self):
        return self._age

    @age.setter
    def age(self, age):
        self._age = age

    def speak(self):
        print('汪汪....')


d = Dog('二哈', 8) # TypeError: __init__() missing 1 required positional argument: 'name'
d.name = '萨摩耶'
print(d.name)
print(d.age)

如果,父类的_init_()方法中有很多的参数,如果如传递的话,会被覆盖掉,而传递过来的话,会增大代码量,有什么方法可以解决吗?

class Animal():

    def __init__(self, name):

        self._name = name

    def run(self):
        print('动物跑....')

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name):
        self._name = name

    def sleep(self):
        print('动物睡觉....')


class Dog(Animal):

    def __init__(self, name, age):
        # 直接调用父类_init_方法,而且还省略了self._name = name步骤,如果参数很多,可以减少代码量
        Animal.__init__(self, name)
        # self._name = name
        self._age = age
    @property
    def age(self):
        return self._age

    @age.setter
    def age(self, age):
        self._age = age

    def speak(self):
        print('汪汪....')


d = Dog('二哈', 8) # TypeError: __init__() missing 1 required positional argument: 'name'
d.name = '萨摩耶'
print(d.name)  # 萨摩耶
print(d.age)   # 8

这样做的话,还有一个问题,这样的调用方法把父类给写死了,如果更换了父类,我们还得更换父类的_init_方法。所以,super() 可以彻底解决这个问题

 
class Animal():

    def __init__(self, name):

        self._name = name

    def run(self):
        print('动物跑....')

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name):
        self._name = name

    def sleep(self):
        print('动物睡觉....')


class Dog(Animal):

    def __init__(self, name, age):
        # 直接调用父类_init_方法,而且还省略了self._name = name步骤,如果参数很多,可以减少代码量
        # Animal.__init__(self, name)
        # 只需要选择传入的参数即可,不会考虑父类是否更换
        super().__init__(name)
        # self._name = name
        self._age = age
    @property
    def age(self):
        return self._age

    @age.setter
    def age(self, age):
        self._age = age

    def speak(self):
        print('汪汪....')


d = Dog('二哈', 8) # TypeError: __init__() missing 1 required positional argument: 'name'
d.name = '萨摩耶'
print(d.name)  # 萨摩耶
print(d.age)   # 8

4. 多重继承

  • 在Python中是支持多重继承的,也就是一个类可以同时拥有多个父类
  • 可以在类名()里面添加多个类,来实现多重继承
  • 在这里插入图片描述
  • 多重继承可以使子类同时用有多个父类,并且会获取到所有父类中的方法
  • 在开发中没有特殊情况应该避免使用多重继承。因为多重继承会使代码更加复杂
  • 如果多个父类中有同名的方法,则会在第一个父类中寻找,然后是第二个、第三个,前面的回覆盖后面的
class A():

    def test(self):
        print('A中的test....')

class B(object):

    def testB(self):
        print('B中的test....')

    def test(self):
        print('B....')
class C(A,B):
    pass

    # def testC(self):
    #     print('C中的test....')

c = C()
c.test()      # A中的test....

class A():

    def test(self):
        print('A中的test....')

class B(object):

    def testB(self):
        print('B中的test....')

    def test(self):
        print('B....')
class C(B, A):
    pass

    # def testC(self):
    #     print('C中的test....')

c = C()
c.test()      # B....

如果第一个类中没有该方法怎么办

class A(object):

    pass

class B(object):

    def testB(self):
        print('B中的test....')

    def test(self):
        print('B....')

class D(object):

    def test(self):
        print('D.....')

class C(A, B, D):
    pass

    # def testC(self):
    #     print('C中的test....')

c = C()
c.test()      # B....

5. 多态

  • 多态是面向对象的三大特性之一, 多态保证程序的灵活性
  • 一个对象可以以不同的形式去出现
class A:
    def __init__(self, name):
        self._name = name

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name):
        self._name = name

class B:

    def __init__(self, name):
        self._name = name

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name):
        self._name = name

class C:
    pass

a = A('葫芦娃')
b = B('钢铁侠')
c = C()

def speak(obj):
    # 对于该函数来说只要对象中有name属性 就可以使用,它就可以作为参数传递
    # 不考虑对象的类型。只要有name属性就可以
    print('Hello %s' % obj.name)
speak(a)

def speak2(obj):
    # 该函数只允许A类的实例进行输出,而其他类型的对象无法使用该函数,这样的话就违反了多态
    if isinstance(obj, A):
        print('Hello %s' % obj.name)
        # print('Hello {}'.format(obj))
speak2(a)


举例:len()函数就是一个典型的多态函数

lst = [1, 2, 3, 4]      
s = 'python'            
print(len(lst))    # 4  
print(len(s))      # 6  

class B:                   
                           
    def __init__(self, name
        self._name = name  
                           
    @property              
    def name(self):        
        return self._name  
                           
    @name.setter           
    def name(self, name):  
        self._name = name  
print(len(b))    # TypeError: object of type 'B' has no len() 
# 只要对象中有__len__特殊方法,就可以通过len()函数获取到长度的结果 
class B:
    def __len__(self):
        return 100

    def __init__(self, name):
        self._name = name

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name):
        self._name = name


print(len(B))  # 100

6. 属性和方法

  • 类属性
    • 类属性直接在类中定义的属性
    • 类属性只能通过类和类的实例才能访问的到,但是类属性只能通过类对象来修改,实例对象无法修改
class A:

     count = 0


a = A()
print(A.count)   # 0
print(a.count)   # 0

# 类属性只能通过类对象来修改,实例对象无法修改——> 类对象和实例对象的值都为100
class A:

     count = 0


a = A()
A.count = 100
print(A.count)  # 100
print(a.count)  # 100

# 我们试着用实例对象去修改会有什么效果——> 类对象的属性值仍然为0,但是实例属性的值为1
class A:

     count = 0


a = A()
a.count = 1
print(A.count)  # 0
print(a.count)  # 1


  • 实例属性
    • 实例属性是通过实例对象添加的属性
    • 实例属性只能通过实例对象才能访问和修改,类对象无法访问和修改
class A(object):

     count = 0

     def __init__(self):
          # 实例属性  通过实例对象添加的属性
          self.name = '钢铁侠'

# 实例属性只有实例对象才能访问和修改,类对象无法访问和修改
a = A()
print(a.name)  # 钢铁侠

# 如果类对象进行访问和修改的话,会报一个属性错误
print(A.name) # AttributeError: type object 'A' has no attribute 'name'


  • 方法
  • 类方法
    • 类方法的格式:@classmethod
    • 类方法传递的第一个参数是 cls 。 cls 是当前类的参数
    • 类方法可以通过实例对象和类对象去调用,而且实例对象调用类方法的时候不需要传入 cls 参数
  • 实例方法
    • 在类定义中,以self为第一个参数的方法皆为实例方法
    • 实例方法在调用的时候,Python会将当前的调用对象以 self 传入, self = 调用对象
    • 实例方法可以通过实例和类去调用
    • 通过类去调用实例方法时,需要手动传入 self 参数
    • 即 实例对象.实例方法() = 类对象.实例方法(实例对象)
class A(object):

     count = 0

     def __init__(self):
          # 实例属性  通过实例对象添加的属性
          self.name = '钢铁侠'

     # 实例方法
     # 在类定义中以第一个self参数传入的的都是实例方法
     # 实例方法在调用的时候,Python会自动将调用对象以self参数传入
     # 类方法调用的时候需要手动传入self参数
     def test(self):

          print('Hello  test....')

     # 类方法
     # 类方法需要传入cls参数
     @classmethod
     def speak(cls):
          print('Hello  speak....')
          print(cls.count)

a = A()
a.test()  # Hello  test....

# 当类方法去调用的时候,不会自动传入self,需要手动去传入一个self参数,否则会报属性错误
# A.test()  # TypeError: test() missing 1 required positional argument: 'self'
A.test(a)  # Hello  test....
# a.test() = A.test(a)

A.speak()  # Hello  speak....    0
a.speak()  # Hello  speak....    0
# 即A.speak() = a.speak()


  • 类方法和实例方法的区别:
    • 实例方法传入的第一参数是self,而类方法传入的第一个参数是cls
    • 类方法需要@classmethod 作为装饰器
  • 静态方法
    • 语法:@staticmethod
    • 静态方法不需要指定任何默认参数
    • 静态方法可以通过类和实例调用
    • 静态方法基本上是一个和当前类无关的方法。它只是一个保存到当前类的函数
    • 静态方法一般是工具方法,与当前类无关
class A(object):
     @staticmethod
     def text():
          print('Hello text....')

a = A()
a.text()  # Hello text....
A.text()  # Hello text....


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值