基础--13、面向对象Ⅱ

在这里插入图片描述

一、封装的引入

  • 封装的基本概念
    • 封装是面向对象的三大特征之一。
    • 封装出现的原因:
      • 1.属性不能随意修改
      • 2.属性不能改为任意的值
    • 封装是指隐藏对象中一些不希望被外部所访问的属性和方法。
    • 我们可以提供一个getter()方法和setter()方法是外部可以访问已经封装的属性。
      • getter()方法用来获取对象中指定的属性
      • setter()方法用来设置对象指定的属性
    • 封装的思想:
      • 1.我们需要一种方式来增强数据的安全性。
      • 2.属性不能随意更改。(允许修改时,才能修改。)
      • 3.属性不能为任意值。
    • 可以为对象的属性使用双下划线开头__xxx。双下划线开头的属性,是对象的隐藏属性,隐藏属性只能在类的内部访问,无法通过对象访问。
    • 其实隐藏属性只不过是python自动为属性改了一个名字——>_累名__属性名,例如__name ——>_Person__name(这种方式实际上依然可以在外部访问,但是这种方式我们一般不用。一般我们会将一些私有属性以单下划线开头)
    • 一般来说,单下划线开头的属性都是私有实行,没有特殊情况下不要修改私有属性。
      封装思想的简单演示:
class Car:
    def __init__(self, name, color):
        self.name = name
        self.color = color

    def run(self):
        print('汽车开始跑了')

    def horn(self):
        print('BIBIBIBIKBI')


car = Car('法拉利','红色')
# print(car.name, car.color)
car.name = '小猫咪'
print(car.name,car.color)
car.run()
car.horn()

打印输出结果:

汽车开始跑了
BIBIBIBIKBI

分析:上述代码应该输出
小猫咪 红色
汽车开始跑了
BIBIBIBIKBI

但是为car实例添加的属性为小猫咪时,小猫咪的这恶搞属性就覆盖了法拉利。
这样就打乱了这一类的代码。导致错误。

二、封装

  • 封装其实是做出一个相对封装的效果。(所谓古语曰:防君子不防小人)
  • 封装演示实例:

1、比较low的封装

class Dog:
    def __init__(self, name):
        self.hidden_name = name


dog = Dog('哈士奇')
# print(dog.hidden_name)
dog.name = '田园犬'
print(dog.hidden_name)

打印输出结果:
哈士奇
分析:使用这种方式过于简单,只是简单的对哈士奇进行了封装,田园犬这个属性没有对哈士奇这个属性产生影响。

2、绝对封装演示:

class Car():

    def __init__(self, name, color):
        # 属性名称   值
        # 这种方式告诉别人这个是私有属性,不要轻易修改
        # __name 叫做完全封装  私有属性
        self.__name = name
        self.__color = color

    def run(self):
        print('汽车开始跑了')

    def laba(self):
        print('滴滴滴')

    # getter方法 setter方法
    # getter方法用查看私有属性  如果只有一个getter方法,没有setter方法:这个属性是一个只读属性
    def get_name(self):
        return self.__name

    # setter方法是用来修改私有属性
    def set_name(self, name):
        self.__name = name


car = Car('奔驰', '黑色')
# _类名__属性名
# print(car._Car__name)
# car.__name = '雪佛兰'  这种方式是外行 没有工作经验的程序员
print(car.get_name())
# print(car.set_name('宝马'))
print(car.get_name())

打印输出结果:

E:\python\python.exe D:/PycharmProjects/基础班第11/day-13/上课代码/01-封装.py
奔驰
奔驰

Process finished with exit code 0

分析:首先,在代码内部定义出了读取方法和修改方法,就证明,该代码内部的封装属性是可以修改的。
总结: 封装确实增加了类的定义的负责程度,但是也保证了数据的安全。

  • 1.隐藏属性名,使调用者无法随意的修改对象中的属性。
  • 2.增加了getter()方法和setter()方法,很好控制属性是否是只读的。
  • 3.使用setter()方法设置属性,可以在再做一个数据的验证。
  • 4.使用getter()方法获取属性,使用setter()方法设置属性可以读取属性和修改属性的同时做一些其他的处理。
    总结:__name的意思是禁止修改此属性(相当于加了一层).

3、真正意义上的封装

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

    # getter()--查看属性方法:(可读)
    def getter_name(self):
        print('用户调用了此读取方法')
        return self._name

    # setter()--修改属性方法:(可写)
    def setter_name(self, name):
        print('用户调用了此修改方法')
        self._name = name


p1 = Person('陈慧翎')
p1.setter_name('周慧敏')
# print(p1._name) # 未调用get方法禁止查看属性
# p1.name = '黄一琳'
# print(p1.name)
print(p1.getter_name())

打印输出结果:

用户调用了此修改方法
用户调用了此读取方法
周慧敏

总结: 封装确实增加了类的定义的负责程度,但是也保证了数据的安全。

  • 1.隐藏属性名,使调用者无法随意的修改对象中的属性。
  • 2.增加了getter()方法和setter()方法,很好控制属性是否是只读的。
  • 3.使用setter()方法设置属性,可以在再做一个数据的验证。
  • 4.使用getter()方法获取属性,使用setter()方法设置属性可以读取属性和修改属性的同时做一些其他的处理。

三、property装饰器

  • property装饰器
  • 我们可以适应@property装饰器来创建只读属性,@property装饰器会将方法转换为相同名称的制只读属性,可以与虽定义的属性配合使用,这样可以防止属性被修改。
    演示示例:
class Person:
    def __init__(self, name):
        self._name = name

    @property # 设置只读属性(与getter方法类似)
    def name(self):
        print('getter方法执行了')
        return self._name

    @name.setter # 代表setter方法
    def name(self, name):
        print('setter方法执行了')
        self._name = name


p1 = Person('周慧敏')
p1.name = '黄一琳'
print(p1.name)

打印输出结果:
setter方法执行了
getter方法执行了
黄一琳

总结:首先通过装饰器设置只读属性,再通过装饰器设置setter可修改属性,就可以告诉其他的同事,这是一个封装的参数,如果需要修改请通过正当方式修改。

四、继承

1、继承的简介

  • 继承是面向对象的三大特性之一。
  • 通过继承我们可以是一个类取到其他类中的属性和方法。
  • 在定义类时,可以在类名后面的括号中指定当前类的父类(超类、基类)
  • 继承提高了类的复用性。让类与类之间产生了关系。有了这个关系,才有了多态的特性。
class Animal():

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

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


# 定义一个狗类
# 1. 直接在动物类上面修改   违反ocp
# 2. 创建一个新的类(狗类)   会出现大量重复的代码
# 3. 直接从动物类中间拿到属性和方法 (推荐)=>  继承:就是在定义类名之后的括号里写上继承的父类(超类)


class Dog(Animal):
    pass


dog = Dog()

dog.run()
dog.sleep()


# 检测是否是类创建的实例对象
res = isinstance(dog, Dog)
print(res)


# 检测是否是当前类的父类  issubclass
res = issubclass(Dog, Animal)
print(res)

# object 是所有类的父类
res = issubclass(Animal, object)
print(res)

打印输出结果:

E:\python\python.exe D:/PycharmProjects/基础班第11/day-13/上课代码/04-继承的使用.py
动物会跑
动物会睡觉
True
True
True

Process finished with exit code 0
  • isinstance检测是否是类创建的实例对象
  • issubclass检测是否当前的父类

2、方法的重写

  • 如果在子类中有和父类同名的方法,则通过子类实例去调用方法时,会调用子类的方法而不是父类的方法,这个特点我们成为方法的重写(覆盖)
  • 当我们调用一个对象的方法时:
    • 会优先调用当前对象中寻找是否具有该方法,如果有则纸直接调用。
    • 如果没有,则去当前父类中寻找,如果父类中有则直接调用父类的方法。
    • 如果没有,则去父类中的父类寻找,以此类推,知道找到object,如果依然没有找到就报错。
class A(object):
    def test(self):
        print('A.....')


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


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


c = C()
c.test()

# 方法的重写: 子类重写父类的方法,会将父类中的方法所覆盖掉   发扬光大的作用才会重写方法

打印输出结果:

E:\python\python.exe D:/PycharmProjects/基础班第11/day-13/上课代码/06-关于方法的重写.py
C......

Process finished with exit code 0

总结:方法的重写就是子类覆盖父类的方法。

3、supper方法及其使用

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

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

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

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

    def get_name(self):
        print('get 方法调用了')
        return self._name


class Dog(object):
    def __init__(self, gender):
        self.gender = gender


class Zhonghua(Animal, Dog):

    def __init__(self, age, name, gender):
        super().__init__(gender)
        super().__init__(name)
        self.gender = gender
        self._name = name
        self.age = age

    def sleep(self):
        super().sleep()
        print('狗会睡觉')

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


dog = Zhonghua('中华田园犬', 18, '男')
dog.sleep()
# print(dog.get_name())

print(type(Zhonghua))
print(issubclass(Zhonghua, type))
print(issubclass(type, object))


# 解耦合  1. 提高问题的解决概率   2. 提高问题的解决效率  3. 提高解决问题的速度  4. 降低爆发隐患的可能性

# 多重继承: 兄弟类中都有相同的方法,那么先调用写到前面的那个类的方法

打印输出结果:

E:\python\python.exe D:/PycharmProjects/基础班第11/day-13/上课代码/05-super方法及其使用.py
动物会睡觉
狗会睡觉
<class 'type'>
False
True

Process finished with exit code 0

总结:通过supper方法可以是在调用子类的方法的同时调用出父类中的相同方法。
注:在输出的时候,会先输出父类中的方法。

、PEP8代码书写规范

  • 缩进使用4个空格,空格是首选的缩进方式,python3不允许混合使用制表符和空格来缩进。
  • 每一行最大长度限制在79个字符以内。
  • 顶层函数、类的定义。前后使用两个空行隔开。
  • import导入
    • 建议在不同的行导入,例如
import os
omport sys

也可以这样:

from subprocess import Popen, PIPE
  • 导包位于文件顶部,在模块注释、文档字符串之后,全局变量、常量之前,导入按照以下顺序分组:
    标准库导入
    相关第三方库导入
    本地应用/库导入
    在每一组导入之间加入空行
  • python中定义字符串使用双引号、单引号是相同的,尽量保持使用同一方式定义字符串,当一个字符串包包含单引号或者双引号时,在做外层使用不同的符号来避免使用反斜杠转译,从而提高可读性。
  • 百搭是个语句中的空格:
    1.避免在小括号、方括号、花括号后跟空格。
    2.避免在都好、分号、冒号之前添加空格。
    3.冒号在切片中就像二元运算符,两边要有相同数量的空格,如果某个切片参数省略,空格也省略。
    4.避免为了和另外一个赋值语句对齐,在赋值运算符附加多个空格。
    5.避免在表达式尾部添加空格,因为表达式尾部空格通常看不见,会产生混乱。
    6.总是在二元运算符两边加一个空格,赋值(=),增量赋值(+=,-=),比较(==,<,>,!=,<>,<=,>=,in,not,in,is.is not),布尔(and,偶然,not)
    7.避免将小的代码和if/for/while放在同一行,要避免代码太长。
 1 if foo == 'blah': do_blah_thing()
 2 for x in lst: total += x
 3 while t < 10: t = delay()
  • 永远不要使用字母’l’(L),o(O)或者大写的I作为字符串的变量,在有些字体里这些字符无法和数字0和1区分。
  • 累名一般使用首字母大写的约定。
  • 函数名应该小写,如果想提高可读性可以用下划线分割
  • 如果函数的参数名和已有的关键词冲突,在做后加单一下划线比缩写或者随意拼写更好。
  • 方法名和实例变量使用下划线分隔的小写单词,以提高可读性。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值