【python】(六)python的封装、继承和多态


1. python面向对象编程

1.1 面向对象是什么

  • Python 是一门面向对象的语言
  • 面向对象编程(OOP):Object Oriented Programming

所谓的面向对象,就是在编程的时候尽可能的去模拟真实的现实世界,按照现实世界中的逻辑去处理问题,分析问题中参与其中的有哪些实体,这些实体应该有什么属性和方法,我们如何通过调用这些实体的属性和方法去解决问题。

1.2 两种编程思想

  1. 面向过程

    • 一种以过程为中心的编程思想
    • 首先分析解决问题所需要的步骤
    • 然后用函数将这些步骤一步一步的实现
    • 最后按顺序依次调用运行
  2. 面向对象

    • 是一种更符合我们人类思维习惯的编程思想
    • 面向对象开发就是不断的创建对象,使用对象,操作对象做事情
    • 可以将复杂的事情简单化

1.3 类与对象

  • 类(class): 用来描述具有相同的属性和方法的对象的集合。它定义了集合中每个对象所共有的属性和方法。
  • 对象(object):也称为类的实例,是一个具体存在的实体。

2. python类与对象

2.1 类的定义

  • class 关键字
# 语法
class 类名(父类名):
    """类的帮助信息"""
    属性
    方法
# class_def.py

# 类的声明
class Human(object): #object可以省略。在python中如果没有声明继承的类的话,那默认继承的是超类object。
    """人类"""
    # 定义属性(类属性)
    message = "这是类属性"

# 通过类访问类属性
print(Human.message)

2.2 类的方法

2.2.1 实例方法

2.2.1.1 构造方法
  • 作用:实例化对象。构造方法用于构造并直接返回该类的对象,每当创建一个类的新的实例时,python会自动执行构造方法,这是创建对象的基本途径。如果开发者没有在类中定义构造方法,python会自动给该类默认添加一个构造方法。
  • 语法:def __init__(self, 参数列表)
    • self:self参数是一个指向实例的引用,用于访问类的属性和方法,在方法调用时会自动绑定到调用这个方法的本身。
    • self参数必须有,且必须处于首位。
  • 访问:类名(参数列表)
# constructor_method.py

class Human:

    # 定义属性(类属性)
    message = "这是类属性"

    # 构造方法
    def __init__(self, name, age):  
        # 实例变量(实例属性)
        self.name = name
        self.age = age
        print("这是构造方法")

# 实例化对象
person = Human("哈利波特", 12)

# 通过实例访问类属性
print(person.message)

# 通过实例访问实例属性
print(person.name)
print(person.age)
2.2.1.2 实例方法
  • 作用:实例方法是在类中定义的函数,该函数是一种在类的实例上操作的函数。实例方法提供每个类的实例共享的方法
  • 语法:def 方法名(self, 参数列表)
    • self:类的实例自身,也可以是self之外的其他单词,但建议使用约定俗成的self。第一个参数必须是self,不可省略。
    • 参数列表:自定义参数,每个参数间使用逗号分隔
  • 访问:实例.方法名(参数列表)
  • 实例方法与函数的区别:函数是实现某个独立功能;实例方法是实现类的某个行为,属于类的部分。实例方法用于定义该类的对象行为和行为实现。在类中的方法都属于实例方法。
# instance_method.py


class Human:

    # 实例方法
    def study(self, course):
        print("正在学习{course}")

# 实例化
person = Human()

# 通过实例访问实例方法
person.study("python")

2.2.2 类方法

  • 作用:类方法是指在类中使用 @classmethod 装饰器装饰的方法。用于设置或获取类的详细信息或者状态。
  • 语法:@classmethod
  • 访问:类名.类方法名(参数列表)
  • 注意:不能访问或者修改实例对象的数据 ,因为类方法绑定的是cls参数不是self参数。不使用cls不会报错,但是最好按照惯例来,cls指向对象其实就是类名本身。
# class_method.py

class Human:

    # 类属性
    population = []

    # 类方法
    @classmethod
    def born(cls): #使用类方法装饰器,定义类时会自动添加cls参数
        print("这是类方法")
        cls.population += 1


# 通过类名访问类方法
Human.born()
print(Human.population)

2.2.3 静态方法

  • 静态方法是类中使用@staticmethod装饰的方法。静态方法不需要访问数据,没有cls、self这种关键字。静态函数可以独立工作,不能设置类的状态或者实例的状态。
  • 作用:静态方法用于创建通用的工具函数。这样就可以把常用的工具函数放在一个类里,使用的时候不需要实例化就可以直接调用。
  • 语法:@staticmethod
  • 调用:类名.静态方法名()
  • 注意:调用类方法和静态方式时,我们是使用类名访问。虽然实例也可以调用类方法和静态方法,但是一般不会这样进行操作。这样可以省去实例化的步骤。
# static_method.py

class Human:

    # 静态方法
    @staticmethod
    def grow_up():#使用静态方法声明后,不会绑定cls或者self参数
        print("这是静态方法")

# 通过类名访问静态方法
Human.grow_up()

3. python封装

3.1 封装的概念

封装(Encapsulation):

  • 隐藏:属性和实现细节,不允许外部直接访问
  • 暴露:公开方法, 实现对内部信息的操作和访问

3.2 封装的作用

  • 限制不合理的访问和操作,提高数据安全性
  • 可进行数据检查,从而有利于保证对象信息的完整性

3.3 封装的实现

3.3.1 隐藏

python中没有既定的关键字或者机制来实现真正的封装,但是使用命名方式来实现

  • 保护属性:_属性名
  • 私有属性:__属性名
    • 定义私有属性之后,python将会自动添加_类名,变相的实现了属性的隐藏,即被视为: _类名__属性名
    • 当想要通过__属性名去访问属性的话,实际上访问不到的。
#定义一个Account类
class Account:

    # 普通属性
    bank = "BOC"
    # 内部属性
    _username = "Hogwarts"
    # 私有属性
    __password = "888"


# 通过类名访问类属性
print(Account.bank)       # 将会打印 BOC
print(Account._username)  # 将会打印 Hogwarts
print(Account.__password) # 将会引发 AttributeError,打印内容:AttributeError: type object 'Account' has no attribute '__password'
print(Account.__dict__)   # 将会打印类中实际有用属性
#打印内容:{'__module__': '__main__', 'bank': 'BOC', '_username': 'Hogwarts', '_Account__password': '888', '__dict__': <attribute '__dict__' of 'Account' objects>, '__weakref__': <attribute '__weakref__' of 'Account' objects>, '__doc__': None}
#注:__dict__:python内置特殊属性,字典格式,保存类中所拥有的可写的属性

3.3.2 暴露

  1. 提供数据访问功能(getter)
  • 计算属性(通过@property合成的属性成为计算属性)
  • 语法:使用@property装饰器
  • 作用:把类中的一个方法变成一个属性
  • 调用:实例.方法名

注意: 计算属性并不真正的存储状态,其值是通过某种算法计算得到的,当程序对该属性赋值时,所赋值实际是存放在对应的实例变量中。

class Account:
    # 普通属性
    bank = "BOC"
    # 内部属性
    _username = "Hogwarts"
    # 私有属性
    __password = "888"

    @property
    def password(self):
        return self.__password

# 实例化对象
obj = Account()

# 访问实例的私有属性
print(obj.password)  # 将会打印 888
#注意:password虽然是方法,但是已经被装饰成计算属性,因此访问的时候不需要加()
  1. 提供数据操作功能(setter)
  • 语法:使用@计算属性名.setter装饰器
  • 作用:对计算属性进行赋值操作
  • 调用:实例.方法名
class Account:
    # 普通属性
    bank = "BOC"
    # 内部属性
    _username = "Hogwarts"
    # 私有属性
    __password = "888"

    @property
    def password(self):
        return self.__password

    @password.setter
    def password(self, value):
        # 增加数据的校验
        if len(value) >= 8:
            self.__password = value
        else:
            print("密码长度最少要有8位!")

# 实例化对象
obj = Account()

# 修改私有属性(满足校验条件)
obj.password = "hogwarts666"  # 修改成功
print(obj.password)  # 将会打印 hogwarts666

# 修改私有属性(不满足校验条件)
obj.password = "123"  # 修改不会生效
print(obj.password)  # 将会打印 888

4. python继承

4.1 继承的概念

继承(Inheritance):

  • 复用父类的公开属性和方法
  • 拓展出新的属性和方法

4.2 继承的实现

  • 语法:class 类名(父类列表)
  • 默认父类是 object
  • Python 支持多继承
# inheritance_demo.py

class Human:
    """人类"""

    # 类属性
    message = "这是Human的类属性"

    # 构造方法
    def __init__(self, name, age):
        # 实例属性
        self.name = name
        self.age = age

    # 实例方法
    def live(self):
        print("住在地球上")


class Student(Human):
    """学生类"""

    def study(self):
        print("正在学习")


# 实例化子类对象
stu = Student("哈利波特", 12)
# 访问类属性(继承)
print(stu.message)
# 访问实例属性(继承)
print(stu.name, stu.age)
# 访问实例方法(继承)
stu.live()
# 访问实例方法(扩展)
stu.study()

4.3 类型检查

  • isinstance(实例, 类名)
    • 检查对象是否是某个类及其派生类的实例
  • issubclass(类名1, 类名2)
    • 检查类名 1 是否是类名 2 的子类
# relation_demo.py

# 人类
class Human:
    pass

# 学生类
class Student(Human):
    pass

# 老师类
class Teacher(Human):
    pass

# 检查实例与类的关系
stu = Student()
print(isinstance(stu, Human))  # 将会打印 True

# 检查类与类的关系
print(issubclass(Student, Human))  # 将会打印 True
print(issubclass(Student, Teacher))  # 将会打印 False

5. python多态

5.1 多态的概念

多态(Polymorphism):同名方法呈现多种行为

python弱类型语言,变量并没有声明类型,因此完全可以在不同的时间代表不同的变量,当同一个变量在调用同一个方法时,完全可能呈现出多种行为,具体呈现的哪些行为由该变量所引用的对象来决定。这就是多态。

5.2 多态的表现

5.2.1 运算符的多态表现

  • +
    • 加法:数字+数字
    • 拼接:字符串+字符串
    • 合并:列表+列表
# 加法:数字+数字
print(1 + 1)  # 打印 2

# 拼接:字符串+字符串
print("Hello" + "World")  # 打印 Hello World

# 合并:列表+列表
print([1, 2] + [3])  # 打印 [1, 2, 3]

5.2.2 函数的多态表现

  • len()函数

    • 可以接收字符串
    • 可以接收列表
# 参数是字符串
print(len("Hogwarts"))

# 参数是列表
print(len([1, 3, 5]))

5.2.3 方法的多态表现

同名变量调用同名方法呈现多种行为。

# poly_method.py

class China:
    def speak(self):
        print("汉语")

class Usa:
    def speak(self):
        print("英语")

# 实例化对象
cn = China()
us = Usa()

for x in (cn, us):
    # 同一个变量在调用同名方法时,呈现不同的行为
    # 具体呈现哪种行为,由该变量所引用的对象决定
    x.speak()

5.3 多态与继承

  • 方法重写(Override):子类的方法名称与父类的相同
  • 重写构造方法
    • super().__init__()
    • 父类名.__init__(self)
# override_demo.py

class Human:
    """人类"""

    message = "这是Human的类属性"

    # 构造方法
    def __init__(self, name, age):
        # 实例属性
        self.name = name
        self.age = age

    # 实例方法
    def live(self):
        print(f"住在地球上")


class Student(Human):
    """学生类"""

    # 重写父类的构造方法
    def __init__(self, name, age, school):
        # 方式一:访问父类的构造方法
        super().__init__(name, age)
  
        #方式二:访问父类的构造方法
        # super(Student, self).__init__(name, age)

        #方式三:访问父类的构造方法
        # Human.__init__(self, name, age)
   
	# 子类特有的实例属性(个性)
        self.school = school

    # 重写父类的实例方法
    def live(self):
        print(f"住在{self.school}")


# 实例化子类对象
stu = Student("哈利波特", 12, "Hogwarts")

# 访问实例方法
stu.live()  # 将会打印 住在Hogwarts
  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值