Python进阶学习(2)面向对象三大特征


面向对象的三大特征:封装,继承,多态

一、封装补充

property装饰器
装饰器:不修改调用方式和源代码基础上,修改或者增加源代码功能

@property 这个内置装饰器,在方法上面装饰就自动加入到property()函数里面

class People:
    def __init__(self, name, age, height, face):
        self.name = name
        self.age = age
        self.height = height
        # __代表隐藏属性,外部不能直接范围
        self.__face = face

    # 我们要统一一个属性调用的规范,我们注意到属性名好像和初始的名字不一样
    # 我们为了进一步和属性一致
    @property  # 这里就是区分出属性和方法
    def face(self):
        # 代表getface,以后看到@property+return就是代表getface
        return self.__face

    # 后面的装饰就要用到@property的函数名+setter或者delter进行装饰
    # setter setface的意思,是固定的语法,不能换名字
    @face.setter
    # 这里的名字必须和@property装饰的函数一致,不能是其他的
    # 修改数值,肯定需要数值进行覆盖修改
    def face(self, face):
        self.__face = face

    @face.deleter  # 删除属性
    # 这里的名字必须和@property装饰的函数一致,不能是其他的
    def face(self):
        # 代码块部分就是代表整个方法
        del self.__face


ziliang = People("梓良", 18, 180, "帅")

print(ziliang.face)

ziliang.face = "丑"
print(ziliang.face)

# 通过动作形式自动分配到对应的方法运行
del ziliang.face
print(ziliang.face)  # 这里会报错,因为删除了

我们不难发现,这样操作仿佛和公共属性没有区别
但是
使用@property装饰器和直接定义公共属性之间确实有一定的区别,主要体现在以下几个方面:

1.访问控制:使用@property装饰器可以实现对属性的访问控制,通过定义getter和setter方法可以对属性进行额外
的逻辑处理。而直接定义的公共属性在外部可以直接访问和修改,无法实现访问控制。

2.属性计算:通过@property装饰器可以实现属性值的计算,getter方法可以根据需要进行计算或逻辑判断。而直
接定义的公共属性的值是固定的,无法实现属性值的动态计算。

3.属性验证:@property装饰器的setter方法可以对属性值进行验证,确保符合特定条件。直接定义的公共属性无
法实现对属性值的验证。

4.属性更新:使用@property装饰器可以在setter方法中实现属性值的更新逻辑,例如更新其他相关属性或执行其
他操作。直接定义的公共属性赋值时无法触发额外的更新逻辑。

5.代码规范性:@property装饰器可以使代码更加规范和易读,将属性的访问、设置和删除操作统一在一个接口
中。这有助于提高代码的可维护性和可读性。

6.因此,虽然@property装饰器和公共属性都可以用来定义类的属性,但@property装饰器提供了更多的功能和
灵活性,可以实现更多属性相关的控制和逻辑处理,而不仅仅是简单的属性存取。

二、继承

1.定义

其实和生物学上的继承一样的道理,子类继承父类的全部属性和方法,除隐藏属性不能继承。单继承就是单亲基础,父类自我繁殖了一个子类

子类copy父类代码的意思,但是子类也可以基因突变,也可以自我重构父类的方法和数学,变成和父类不一样

继承可以解决类与类之间代码冗余

记住python创建的所有类都有一个祖宗:object基类

在Python中,类的继承通过在类定义时在类名后面的括号中指定父类来实现。
如果一个类没有指定父类,则默认继承自object类,
即class ClassName:相当于class ClassName(object):。

在python3都是自动默认继承基类,所以可以省略不写

2.单继承

一个子类继承一个父类

隐藏属性,隐藏方法不能继承

class GrandFather:
    def __init__(self):
        self.money = 1000000
        # 代码私房钱
        self.__privateMoney = 100000

    def house(self):
        print(f"北京四合院一套")

    def setInfo(self):
        # f-String 格式化输出
        print(f"爷爷的遗产:{self.money}")

    # 虽然隐藏属性是不能继承的,但是通过公开的方法去获取隐藏属性是可以的
    # 隐藏方法:__方法名
    # 有些方法你不想直接给外面,你可以隐藏起来
    def __setPrivateMoney(self):
        return self.__privateMoney

    def func(self):
        # 通过公开方法调用隐藏方法
        # 函数调用代表:执行函数的代码
        return self.__setPrivateMoney()


class Father(GrandFather):#指定父类是GrandFather
    def __init__(self):
        super(Father, self).__init__()#确保父类的初始化操作也被执行
#通过super()函数调用父类的方法时,
#并不需要实例化父类对象,而是通过特殊的代理对象来实现方法的调用和方法解析。
#这种机制使得Python的多重继承更加灵活和方便,同时避免了创建多余的父类实例。
        self.__privateMoney = 10000


class Son(Father):
    # 第一个初始化是son的属性
    def __init__(self):
        # 继承父类
        # 初始化父类Father的属性
        super(Son, self).__init__()
        self.__privateMoney = -1000

    def setInfo(self):
        # 这里需要传入你son 的对象
        # 这里如果你调用是父类或者祖宗类,因为不是从父类创建或者祖宗类创建的对象,父类的self是没有的
        # 你需要手动把你的对象传入进去

        # 函数+参数传递,基础课的传递
        Father.setInfo(self)


    def setHouse(self):
        Father.house(self)


son1 = Son()
son1.setInfo()
son1.setHouse()
print(son1.func())

补充:super关键字的作用

①作用

super() 是一个内置函数,用于调用父类的方法。在Python中,当子类继承父类时,可以使用 super() 来调用父类的方法,以便在子类中扩展或重写这些方法而不破坏继承关系。

通过 super() 可以实现以下几点作用:

  1. 在子类中调用父类的方法:通过 super().method_name() 可以在子类中调用父类的方法。
  2. 支持多重继承:super() 确保方法按照继承顺序(MRO,Method Resolution Order)依次调用,避免了钻石继承等多重继承带来的问题。
  3. 简化代码:使用 super() 可以使代码更加清晰和简洁,避免直接指定父类名称。

下面是一个简单的示例,演示了在子类中使用 super() 调用父类方法的情况:

class Parent:
    def show(self):
        print("Parent method")

class Child(Parent):
    def show(self):
        super().show()  # 调用父类的方法
        print("Child method")

child = Child()
child.show()

在这个示例中,子类 Child 中的 show() 方法通过 super().show() 调用了父类 Parent 中的 show() 方法,从而保留了父类方法的功能并在其基础上进行了扩展。

②参数

super() 函数中,参数用于指定子类和实例,以便在多重继承的情况下正确地调用父类的方法。super() 函数的语法如下:

super([type[, object-or-type]])

其中参数的作用如下:

  • type:用于指定当前类的类型。如果在实例方法中使用 super(),通常可以省略这个参数,Python会自动获取当前方法所在的类。如果在类方法或静态方法中使用 super(),则需要显式指定当前类的类型。
  • object-or-type:用于指定当前实例或类。如果在实例方法中使用 super(),通常可以省略这个参数,Python会自动获取当前方法所在的实例。如果在类方法中使用 super(),则需要传入当前类的类型。

在绝大多数情况下,我们可以在实例方法中使用 super() 而无需显式传入参数,因为Python会自动获取当前类和实例。例如:

class Parent:
    def __init__(self):
        print("Parent init")

class Child(Parent):
    def __init__(self):
        super().__init()  # 自动获取当前类和实例
        print("Child init")

child = Child()

在这个例子中,super().__init() 中的 super() 自动获取了当前类 Child 和实例 child,并调用了父类 Parent__init__ 方法。

如果需要在类方法静态方法中使用 super(),则需要显式传入当前类的类型和实例。例如:

class MyClass:
    @classmethod
    def do_something(cls):
        super(MyClass, cls).do_something_static()

    @staticmethod
    def do_something_static():
        print("Doing something static")

MyClass.do_something()

在这个例子中,在类方法 do_something 中,我们显式传入了当前类 MyClass 和当前类的类型 cls,以确保正确地调用父类的方法。

3.重写父类中的属性与方法

class Father:
    def __init__(self, height, eye,age):
        self.height = height
        self.eye = eye
        # 年龄是不能继承
        self.__age = age

    def Money(self):
        print("老爸工资1w")


# 括号里面是你想要继承的父类
# 子类可以修改父类的某些属性
class Son(Father):
    def __init__(self, height, eye, name):
        # 这里需要用到一个super的函数进行初始化父类的属性,代表你
        # 拿到了属性可以进行覆盖修改
        # 如果没有super,就无法修改里面的数值
        # 没有super只有只读权限,没有修改权限,用了super就变成
        #超级管理员,你可以修改上面的属性数值了
        super(Son, self).__init__(height, eye,age)
#调用super(son, self).__init__(height, eye, age)时,
#传入age参数是因为Father类的__init__方法需要height、
#eye和age这三个参数来正确初始化父类的属性。即使子类不直
#接访问父类的属性,但是在构造子类对象时,需要确保父类的
#初始化工作完成,以保证整个继承链的正确性。
        self.name = name

    def Money(self):
        print("你们的工资1.5k, 老爸发的")


father1 = Father("170", "黑色")
son1 = Son("180", "美瞳白色", "xxx1")

print(father1.height, father1.eye)
print(son1.height, son1.eye)
father1.Money()
son1.Money()

4.多层继承

多层继承就是还有爷爷

class GrandFather:
    def __init__(self):
        self.money = 1000000
        # 代码私房钱
        self.__privateMoney = 100000

    def house(self):
        print(f"北京四合院一套")

    def setInfo(self):
        # f-String 格式化输出
        print(f"爷爷的遗产:{self.money}")

    # 虽然隐藏属性是不能继承的,但是通过公开的方法去获取隐藏属性是可以的
    # 隐藏方法:__方法名
    # 有些方法你不想直接给外面,你可以隐藏起来
    def __setPrivateMoney(self):
        return self.__privateMoney

    def func(self):
        # 通过公开方法调用隐藏方法
        # 函数调用代表:执行函数的代码
        self.__setPrivateMoney()


class Father(GrandFather):
    def __init__(self):
        super(Father, self).__init__()
        self.__privateMoney = 10000


class Son(Father):
    # 第一个初始化是son的属性
    def __init__(self):
        # 继承父类
        # 初始化父类Father的属性
        super(Son, self).__init__()
        self.__privateMoney = -1000

    def setInfo(self):
        # 这里需要传入你son 的对象
        # 这里如果你调用是父类或者祖宗类,因为不是从父类创建或
        #者祖宗类创建的对象,父类的self是没有的
        # 你需要手动把你的对象传入进去

        # 函数+参数传递,基础课的传递
        Father.setInfo(self)


    def setHouse(self):
        Father.house(self)


son1 = Son()
son1.setInfo()
son1.setHouse()

5.多继承

就是一个儿子有很多个老爸

吕布

# 多继承
class DingYuan:
    def __init__(self):
        self.fatherName = "丁原义父"

    def setOffices(self):
        print("升官为主簿")


class DongZhuo:
    def __init__(self):
        self.fatherName = "董卓义父"

    def setOffices(self):
        print("送赤兔马")


class WangYun:
    def __init__(self):
        self.fatherName = "王允义父"

    def setOffice(self):
        print("送貂蝉")

# 
class LvBu( DingYuan, WangYun , DongZhuo):
    def __init__(self):
        super(LvBu, self).__init__()


    def setOffices(self):
        WangYun.setOffice(self)
        DongZhuo.setOffices(self)
        DingYuan.setOffices(self)


lvbu = LvBu()
lvbu.setOffices()

# mro就是看继承的顺序
print(LvBu.__mro__)
print(DongZhuo.__mro__)
#在Python中,类的继承顺序是按照从左到右的顺序来决定的。
#这种继承方式称为广度优先,即首先查找当前类,
#然后按照从左到右的顺序逐级向上查找父类,直到找到为止。

# 只看父类顺序
print(LvBu.__bases__)

# 同一个属性名遵守就近原则
print(lvbu.fatherName)

三、多态

一个对象的多种状态
不同的对象,调用同一个方法,表现出不同形式
多态的实现遵守两个原则
1.必须要有类的继承 2.子类必须重写父类的方法

class Money:
    def ticke(self):
        print("车票单价")


class Car(Money):
    def ticke(self):
        print("票价是200元")


class Bus(Money):
    def ticke(self):
        print("票价150元")


class Train(Money):
    def ticke(self):
        print("票价120元")


c = Car()
b = Bus()
t = Train()

c.ticke()
b.ticke()
t.ticke()

也就是把方法类化

  • 51
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只特立独行猪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值