Python语法进阶学习--面向对象

上篇文章中学习了模块和包的几个概念,接下来就进入面向对象的学习。

一.类和对象

1.1 类

概念

  • 很多事物存在相同的属性和行为(也叫方法),比如人有姓名年龄,能吃饭睡觉等等
  • 描述具有共同特征的事物的抽象,称为 类 (class)

组成部分

  • 属性(变量):比如姓名,年龄,身高,肤色等
  • 方法(函数):比如吃饭,睡觉,飞行,歌唱等

1.2 对象

对象是类的实例,是具体的实体。

1.3 类和对象的关系

  • 类相当于图纸(抽象),对象相当于根据图纸制造的实物(具体)
  • 每个对象必须有一个对应的类

1.4 面向对象的特点

封装、继承、多态

  • 封装
    • 将属性和方法放到一起封装成一个整体(定义类),然后通过实例化对象来使用
    • 对属性和方法增加访问权限控制:公开权限、私有权限
  • 继承
    • 子类可以继承父类,子类继承父类之后,子类就拥有了父类中的属性和方法
    • 重写:子类从父类继承过来的方法,不满足子类需要或不完全满足子类需要
    • 私有和继承
  • 多态:同一个代码,由于传入的实例对象的不同,最终代码的调用有不同的效果,这就叫多态

1.5 类的魔法方法

1.5.1 __init__方法:初始化方法

1.5.2 __str__方法:打印方法

1.5.3 __del__方法:删除方法

以下示例中,创建一个Student类,在Student类中有一个初始化方法,在初始化方法中设置了一个实例属性,在创建对象并调用类时,会自动调用初始方法;有一个打印方法,在打印对象的时候会自动调用该方法;有一个删除方法,在删除对象的时候,会自动调用该方法。

class Student:
    def __init__(self):
        print("对象进行初始化操作")
        self.name = '小学生'

    def __str__(self):
        return f'名称叫{self.name}'

    def __del__(self):
        print("对象被删除了")


s1 = Student()
print(s1)

# 删除对象
del s1

__del__总结
1- 代码运行结束后,会进行垃圾回收,垃圾回收的时候就会删除对象,也就是会调用该方法
2- 如果del删除对象,也会触发调用__del__方法
3- 该方法主要作用:一般用来释放相关资源,例如:关闭文件、关闭数据库连接(重资源的操作)

二.封装

2.1 公开权限和私有权限

  • 公开属性、公开方法:随便调用
  • 私有属性、私有方法:
    • 只能在类定义的内部调用
    • 以两个下划线开头__的都是私有权限

私有权限总结:
1- 前面加__来表示是私有
2- 外部无法直接访问私有权限的属性或者方法
3- 在类的内部,可以正常访问私有的属性或者方法
4- 强制访问私有属性或者方法的写法:实例对象名._类名__私有属性或者方法

伪代码示例

class Women:
    """"""
    def __init__(self, name):
        self.name = name # 公开属性
        self.__age = 18 # 私有属性
    def func1(self):
        # 公开方法
        print(self.name)
        print(self.__age) # 可以调用
        print(self.__func2()) # 可以调用

    def __func2(self):
        # 私有方法
        print(self.name)
        print(self.__age)

lady = Women('lady gaga')
lady.func1()
# lady.__func2() # 不可以调用
# print(lady.__age) # 不可以调用

# 实例对象._类名__属性或方法名 可强行突破!但不推荐
print(lady._Women__age) # 强行调用私有属性
lady._Women__func2() # 强行调用私有方法

2.2 封装进阶

2.2.1 类属性和实例属性

类属性名称和实例属性名称相同的时候,使用实例属性

2.2.2 实例方法

所有实例对象都能够调用的方法

2.2.3 类方法

1- @classmethod的装饰器。
2- 调用的时候,推荐使用类名进行调用。不推荐使用实例对象名进行调用
3- 类方法里面只能操作类属性
4- 类方法的作用:一般也是用来对公共资源进行初始化操作

2.2.4 静态方法

1- @staticmethod的装饰器
2- 调用的时候,推荐使用类名进行调用。不推荐使用实例对象名进行调用
3- 静态方法里面不能操作任何类型的属性
4- 静态方法的作用:一般也是用来对公共资源进行初始化操作

静态方法中不能操作类属性和实例属性、类方法、实例方法

封装总结

1- 我们进行类的定义、方法的定义,这些操作,都称之为封装
2- 封装里面的私有权限,用来对外部屏蔽类内部的底层细节,不对外暴露
3- 分为私有属性和私有方法。命名的时候在前面使用两个下划线__,用来表示私有
4- 私有属性和方法,正常只能在类的内部访问
5- 私有属性和方法,可以通过保留方式在类的外部访问。也就是 实例对象名称._类名__私有属性和方法。该方式不推荐

三.继承

3.1 概念

  • 类的继承:在面向对象编程中,子类可以直接继承父类,从而使子类直接具备父类的能力(属性和方法)【代码复用】
  • 继承作用:解决代码重用问题,提高开发效率
  • 注意
    • 站在父类的角度来看,父类派生出子类
    • 站在子类的角度来看,子类继承于父类
    • 父类也叫基类,子类也叫派生类
    • object 是 python 中所有类的父类

3.2 多继承

一个子类可以继承多个父类

class SmallDog(object):
    def eat(self):
        print('小口吃东西')

    def sleep(self):
        print('小憩一会')


class BigDog(object):
    def drink(self):
        print('大口喝水')

    def sleep(self):
        print('呼呼大睡')

# 多继承 默认调用先继承的那个父类中的同名方法
# SuperDog 类定义时同时继承了 SmallDog 和 BigDog
class SuperDog(BigDog, SmallDog):
    pass


# 创建一个 SuperDog 对象
sd1 = SuperDog()
# SuperDog 从 SmallDog 继承了 eat 方法
sd1.eat()
# SuperDog 从 BigDog 继承了 drink 方法
sd1.drink()
# 默认调用先继承的那个父类中的同名方法
sd1.sleep()

3.3 继承多层传递

子类A可以继承子类B,子类B再继承一个父类C,那么子类A也继承了父类C

# 爷爷类
class Animal(object):
    """动物类"""
    def eat(self):
        print('吃东西')

# 爸爸类
class Dog(Animal):
    """狗类"""
    def drink(self):
        print('喝水')

# 儿子类
class SuperDog(Dog):
    pass

# 创建一个 SuperDog 对象
sd1 = SuperDog()
sd1.eat()
sd1.drink()

3.4 重写父类方法

  • 重写父类(包括爷爷类及以上)方法:
    • 从父类继承的方法不能满足子类的需要,为了拓展功能而重新定义了同名函数
    • 重写形式:
      • 在子类中定义了一个和父类(包括爷爷类及以上)同名的方法(参数也一样),即为对父类(包括爷爷类及以上)的方法重写
    • 重写之后子类调用同名方法,默认只会调用子类的
  • 类继承存在顺序链:
    • 定义类名时从左到右的顺序,左边是右边的子类
    • class SuperDog(SmallDog, BigDog): 这个继承顺序为 继承顺序:SuperDog->SmallDog->BigDog
  • 子类调用父类被重写方法:在子类方法中还想调用父类的同名方法。可以使用如下方式:
    • 父类名.同名方法(self, 形参1, ……)
    • super(顺序链目标类左边的类名, self).同名方法(...)
class SmallDog(object):
    def eat(self):
        print('吃小东西')
class BigDog(object):
    def eat(self):
        print('啃大骨头')

class SuperDog(SmallDog, BigDog):
    # todo 继承顺序:SuperDog->SmallDog->BigDog
    def eat(self):
        print('--方式1:父类名.同名方法(self, ...)--')
        # 需求1:调用 SmallDog 父类的 eat 方法
        SmallDog.eat(self)
        # 需求2:调用 BigDog 父类的 eat 方法
        BigDog.eat(self)
        print('--方式2:super(顺序链目标类左边的类名, self).同名方法(...)--')
        # 需求1:调用 SmallDog 父类的 eat 方法
        super(SuperDog, self).eat()
        # 需求2:调用 BigDog 父类的 eat 方法
        super(SmallDog, self).eat()
        # 本质:super(顺序链上目标父类左边的子类, self).目标父类的同名方法()
        print('--方式3:super().同名方法(...)--')
        # 需求1:调用 SmallDog 父类的 eat 方法
        super().eat() # 与super(SuperDog, self).eat()相同

# 类的继承顺序链:在python中,一个类可以继承多个类,
# 而且父类还可能有父类,对于这种情况,类的继承是有一个先后顺序,
# 这个顺序就叫继承顺序链。
# 如何查看一个类的继承顺序链:类名.__mro__
print(SuperDog.__mro__)

# 创建一个 SuperDog 对象
sd1 = SuperDog()
sd1.eat()

3.5 继承链

总结: 多继承中,继承有先后顺序,先继承的是第一个父类

class A:
    def func(self):
        print("A_的打印输出")

class C(A):
    def func(self):
        super().func()
        print("C_的打印输出")

class B(A):
    def func(self):
        super().func()
        print("B_的打印输出")

class D(B,C):
    def func(self):
        super().func()
        print("D_的打印输出")

# 从D角度出发,继承顺序如下:D->B->C->A
# 多继承中,有继承先后顺序,先继承的是第一个父类
d = D()
d.func()
print(D.__mro__)#能够打印出继承链

3.6 禁止私有继承

1- 私有的属性和方法不能被子类继承
2- 面向对象中,封装(私有权限)的主要作用,是用来对外屏蔽一些底层实现细节,对外提供更加安全/好用的方法
举例:PC电脑,只是对消费者暴露键盘、屏幕、USB接口等简单的操作

class Animal:
    def __init__(self):
        self.name = '动物'
        # 私有属性
        self.__age = 2

    # 私有方法
    def __pee(self):
        print("动物拉粑粑")

    """
        面向对象中,封装(私有权限)的主要作用,是用来对外屏蔽一些底层实现细节,对外提供更加安全/好用的方法
        举例:PC电脑,只是对消费者暴露键盘、屏幕、USB接口等简单的操作
    """
    def show_info(self):
        self.__pee()
        print(self.__age)

class Dog(Animal):
    pass

d = Dog()
d.show_info()
# d.__pee()
# print(d.__age)

# 暴力方式访问(不推荐)
d._Animal__pee()
print(d._Animal__age)

继承总结

1- 继承:子类从父类中获得相关的方法和属性,该过程称之为继承。不能继承私有属性和方法
2- 继承分类:单继承、多继承、多层继承
3- 继承之后,子类可以重写父类的方法。一般什么情况下会重写?子类需要加强或者改造方法的时候
4- 在子类方法里,调用父类的方法,可以通过如下三种方式:
4.1 (推荐)父类类名.方法名(self,实参1,实参2…)
4.2 super(子类类名,self).方法名(实参1,实参2…)
4.3 super().方法名(实参1,实参2…)
5- 多继承的顺序关系
class A:
class B(A):
class C(A):
class D(B, C):
上面代码的继承关系,【从D的角度出发】,D>B>C>A

四.多态

概念

同一个代码,由于传入实例对象的不同,最终有不同的调用效果!
Python是动态语言,站在代码写手的角度,本身就是多态,不存在非多态的情况

def add(a, b):
    return a + b
res = add(1, 2)
print(res) # 3
res = add('hello', 'world')
print(res) # helloworld

你可能感兴趣的:(python,学习,开发语言,类和对象,封装继承多态)