学习Python第12天_封装&继承&重写

仅记录个人学习Python所学,学识浅薄,若有错误欢迎指出。文章可能会不太完善,后续可能会继续更新。

一、封装

广义的封装:函数和类的定义本身,就是封装的体现

狭义的封装:一个类的某些属性,在使用的过程 中,不希望被外界直接访问,而是把这个属性给作为私有的【只有当前类持有】,然后暴露给外界一个访问的方法即可【间接访问属性】

封装的本质:就是属性私有化的过程

封装的好处:提高了数据的安全性,提高了数据的复用性

如果想让成员变量不被外界直接访问,则可以在属性名称的前面添加两个下划线__,成员变量则被称为私有成员变量

私有属性的特点:只能在类的内部直接被访问,在外界不能直接访问

#   私有属性和私有方法
#   面向对象的特征:
#       1.封装
#       2.继承
#       3.多态(了解)

# 1.封装
#   封装了属性和方法
#

# 类
class Person:
    def __init__(self, name, age, sex):
        self.name = name  # 公有属性
        self.__age = age  # 私有属性:双下划线开头的属性  只能在当前类的内部使用
        self._sex = sex  # 公有属性, 但不建议这么写 这里只有一个下划线,有歧义

    def run(self):
        print(self.__age)
        self.__eat()

    # 私有方法
    def __eat(self):
        print('eat')


# 对象
p = Person('鹿晗', 30, '男')
print(p.name)
# print(p.__age)    # 报错 'Person' object has no attribute '__age'
print(p._sex)	# 单下划线方法仍是公有方法,可以调用
p.run()
# p.__eat()           # 报错,__eat()是私有方法

下面的方式可以调用私有方法或私有属性,但是不要这么用
当Python访问私有变量时就是这样访问的,不过既然是私有属性就不要随意访问了

print(p._Person__age)
p._Person__eat()

二、@property装饰器

get函数和set函数并不是系统的函数,而是自定义的,为了和封装的概念相吻合,起名为getXxx和setXxx

get函数:获取值

set函数:赋值【传值】

装饰器的作用:可以给函数动态添加功能,对于类的成员方法,装饰器一样起作用

Python内置的@property装饰器的作用:将一个函数变成属性使用

@property装饰器:简化get函数和set函数

使用:@property装饰器作用相当于get函数,同时,会生成一个新的装饰器@属性名.settter,相当于set函数的作用

作用:使用在类中的成员函数中,可以简化代码,同时可以保证对参数做校验

#   property 装饰器
class Person:
    def __init__(self, name, wechat):
        self.name = name
        self.__wechat = wechat

    # # getter 间接获取私有属性
    # def get_wechat(self):
    #     return self.__wechat
    #
    # # setter 间接修改私有属性
    # def set_wechat(self, new_wechat):
    #     self.__wechat = new_wechat

    @property  # 作用:让get函数可以当成属性来调用
    def wechat(self):
        return self.__wechat

    @wechat.setter	# 这里的命名要和property中函数名称一样
    def wechat(self, new_wechat):
        self.__wechat = new_wechat

    @property
    def photo(self):
        s = self.name + self.wechat
        return s


# 对象
p = Person('刘亦菲', '110')
# print(p.get_wechat())
# p.set_wechat('123')
# print(p.get_wechat())

print(p.wechat)
p.wechat = '120'
print(p.wechat)
# 原本所写函数需要通过对象进行调用,但是添加了@property装饰器后,可以通过函数名之间调用

print(p.photo)

三、私有方法、类方法、静态方法

如果类中的一个函数名前面添加__,则认为这个成员函数时私有化的

特点:也不能在外界直接调用,只能在类的内类调用

类方法:使用@classmethod装饰器修饰的方法,被称为类方法,可以通过类名调用,也可以通过对象调用,但是一般情况下使用类名调用

静态方法:使用@staticmethod装饰器修饰的方法,被称为静态方法,可以通过类名调用,也可以通过对象调用,但是一般情况下使用类名调用

#   类方法和静态方法
class Dog:
    age = 2

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

    def run(self):
        print('成员方法/公有方法')

    def __eat(self):
        print('私有方法:只能在当前类内部使用')

    # 类方法:
    #       1.可以用类和对象调用,推荐用类调用,可以节省内存
    #       2.类方法内部是不可以使用对象属性和其他成员方法或私有方法
    #       3.类方法内部可以使用其他  类方法或类属性
    @classmethod
    def sleep(cls):
        print('类方法:', cls == Dog)
        print(cls.age)  # 调用类属性

    # 静态方法:
    #       1. 可以用类和对象调用,推荐用类调用,节省内存
    #       2. 静态方法内部是不可以使用对象属性和其他成员方法或私有方法
    #       3. 也不建议去使用类属性和类方法,一般写成静态方法的就是一个普通函数,放在类里面
    @staticmethod
    def swim():
        print('静态方法')


# 创建对象
d = Dog('哮天犬')
d.sleep()  # 类方法: True
Dog.sleep()  # 类方法: True
d.swim()
Dog.swim()

四、继承

如果两个或者两个以上的类具有相同的属性或者成员方法,我们可以抽取一个类出来,在抽取的类中声明公共的部分

​ 被抽取出来的类:父类,基类,超类,根类

​ 两个或者两个以上的类:子类,派生类

​ 他们之间的关系:子类 继承自 父类

注意:

​ a.object是所有类的父类,如果一个类没有显式指明它的父类,则默认为object

​ b.简化代码,提高代码的复用性

单继承
简单来说,一个子类只能有一个父类,被称为单继承

语法:

父类:

class 父类类名(object):

​ 类体【所有子类公共的部分】

子类:

class 子类类名(父类类名):

​ 类体【子类特有的属性和成员方法】

说明:一般情况下,如果一个类没有显式的指明父类,则统统书写为object

# 继承

# object: 根类,超类,顶级的类

# 单继承: 只有一个父类
# 多继承: 有多个父类

# 父类:基类


class Ipad(object):
    def __init__(self, price):
        self.price = price

    def movie(self):
        print('看电影')


# 子类:派生类
class Iphone(Ipad):
    def __init__(self, price, color):
        # 需要调用父类的init方法: 对父类属性进行初始化
        # Ipad.__init__(self, price)    # 显式调用
        super().__init__(price)  # 隐式调用
        self.color = color


# 子类
class Iwatch(Iphone):
    def __init__(self, price, color, size):
        super().__init__(price, color)
        self.size = size

    def health(self):
        print(self.price)
        # print(self.__color)   # 不能使用父类的私有属性和私有方法  私有属性和私有方法不能继承


# 对象
# iphone = Iphone(1000, 'green')
# print(iphone.price, iphone.color)
# iphone.movie()

# iwatch = Iwatch(2000, 'green', '3.5')
# print(iwatch.price, iwatch.size)
# iwatch.movie()
# iwatch.health()

一个子类可以有多个父类

语法:

class 子类类名(父类1,父类2,父类3.。。。):

​ 类体

# 多继承
# 父类
class Father:
    def __init__(self, name):
        self.name = name

    def run(self):
        print('会跑步')


# 父类
class Mother:
    def __init__(self, age):
        self.age = age

    def cook(self):
        print('会做饭')


# 子类
class Son(Father, Mother):
    def __init__(self, name, age, height):
        # Father.__init__(self, name)
        # Mother.__init__(self, age)

        # super(Son, self).__init__(name)
        super().__init__(name)  # 继承Father
        super(Father, self).__init__(age)  # 继承Mother
        self.height = height
# 这里super()会比较难理解 上面的(Father,Mother) 决定了后面两个super()中的参数,
# 由于继承链的缘故(继承链在下面),这里需要先继承父亲类,再继承母亲类,如果换成(Mother,Father)
# 继承顺序就会变为先继承母亲类再继承父亲类

# 对象
son = Son('哪吒', 8, 1)
print(son.name, son.age, son.height)
son.run()
son.cook()

# mro 算法:从左往右继承链
# (<class '__main__.Son'>,
# <class '__main__.Father'>,
# <class '__main__.Mother'>,
# <class 'object'>)
print(Son.__mro__)

五、函数重写

在子类中出现和父类同名的函数,则认为该函数是对父类中函数的重写

#   重写: 方法重写

class Person:
    def __init__(self, name):
        self.name = name

    def jump(self):
        print('跳2米远')


class Player(Person):
    def __init__(self, name):
        super().__init__(name)

    # 重写了父类的jump
    def jump(self):
        print('跳4米远')


# 对象
p = Person('宝强')
p.jump()

p2 = Player('姚明')
p2.jump()

六、多态

一种事物的多种体现形式,函数的重写其实就是多态的一种体现

在Python中,多态指的是父类的引用指向子类的对象

# 多态: 在继承的基础上,多个子类重写父类的同一个方法
#       在不同的子类中写不同的功能,那么用父类的对象指向不同的子类,
#       调用该方法,则可以实现不同的功能

# 父类
class Animal:
    def eat(self):
        pass


# 子类
class Dog(Animal):
    def eat(self):
        print('吃骨头')


class Cat(Animal):
    def eat(self):
        print('吃鱼')


class Cow(Animal):
    def eat(self):
        print('吃草')


#
class Person:
    def __init__(self, name):
        self.name = name

    def keep(self, animal):
        print(f'{self.name}养了一只小动物')
        animal.eat()


# 创建对象
dog = Dog()
cat = Cat()
cow = Cow()

#
p = Person('张三')
p.keep(dog)
p.keep(cat)
p.keep(cow)
七、类中常用方法-魔术方法

__ name __
通过类名访问,获取类名字符串
不能通过对象访问,否则报错

__ dict __
通过类名访问,获取指定类的信息【类方法,静态方法,成员方法】,返回的是一个字典
通过对象访问,获取的该对象的信息【所有的属性和值】,,返回的是一个字典

__ bases __
通过类名访问,查看指定类的所有的父类【基类】

class Man:
    pass


class Boy(Man):
    # __init__(): 魔术方法
    def __init__(self, name, age):
        self.name = name
        self.age = age

    # 运算符重载(了解)
    def __add__(self, other):
        # return self.age + other.age
        return Boy(self.name + other.name, self.age + other.age)


# 对象
b = Boy('易烊千玺', 19)
print(__name__)
print(Boy.__name__)  # Boy

print(b.__dict__)   # {'name': '易烊千玺', 'age': 19}
print(b.__module__)  # __main__     所属模块
print(Boy.__module__)   # __main__  所属模块

print(b.__class__)  # <class '__main__.Boy'>    对象所属的类
print(Boy.__bases__)    # __bases__ 所有父类    (<class '__main__.Man'>,)

b2 = Boy('王源', 20)
b3 = b + b2
print(b3.name, b3.age)

__ str __

# __str__

class Cat:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    # 1. 必须返回字符串
    # 2. 作用是让打印的对象的值是这里的返回值
    def __str__(self):
        return f'姓名:{self.name}, 年龄:{self.age}'

    # 优先使用str
    # def __repr__(self):
    #     return f'姓名2:{self.name}, 年龄2:{self.age}'


cat = Cat('tom', 3)
print(cat)
# <__main__.Cat object at 0x0000026709188B00>
# 姓名:tom, 年龄3

# print(repr(cat))  # 姓名2:tom, 年龄2:3
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值