AI学习 Day09 面向对象基础(下)

本文章最初发布在 XJHui’s Blog,未经允许,任何人禁止转载!

注意:最新修改版本已发布在 这里,点击前往查看!

私有化属性

有些属性不想让别人随意修改或者防止被意外修改,就要对属性进行私有化

基本概述

  1. 定义:

    为了保证属性安全(不能被随意修改),可以将属性定义为私有属性

  2. 使用场景:

    • 属性不想被类的外部直接调用
    • 属性值不想随意被改变
    • 不想被子类继承
  3. 语法:

class Person:
__name = ‘张三’ # 属性名前加两个下划线将该属性私有化


## 使用私有属性

1. 案例:验证实例属性私有化后在类的外部不可调用

```python
class Person:
    def __init__(self):
        self.name = '张三'  # 实例属性
        self.__age = 17  # 私有属性
        pass

    pass


p1 = Person()
print(p1.name)  # 打印实例属性

运行结果:

AI学习 Day09 面向对象基础(下)_第1张图片
print(p1.age)  # 打印私有属性

运行结果:

AI学习 Day09 面向对象基础(下)_第2张图片
  1. 案例:验证私有化属性可在类的内部调用

    class Person:
           def __init__(self):
               self.name = '张三'
               self.__age = 17
               pass
       
           def printData(self):  # 实例方法,打印私有属性age
               print(self.__age)
       
           pass
       
       
       p1 = Person()
       p1.printData()  # 通过调用实例方法,验证在类的内部可直接访问私有属性
    

    运行结果:

    AI学习 Day09 面向对象基础(下)_第3张图片

    总结:将属性私有化后,就不可以在类的外部访问了,但内部使用不受任何影响

  2. 私有化属性可继承性:

    class Person:  # 父类
        def __init__(self):
            self.__name = '张三'
            pass
    
        pass
    
    
    class Teacher(Person):  # 子类调用父类
        def test(self):  # 子类中打印父类中的私有属性
            print(self.__name)
    
    
    t1 = Teacher()
    t1.test()
    

    运行结果:

    AI学习 Day09 面向对象基础(下)_第4张图片

    总结:父类的私有属性不可被子类继承

私有化方法

有些重要的方法,不允许外部调用或防止子类意外重写,可以把普通方法设置成私有化方法

语法规则

class Animal:
    def __showInfo(self):  # 方法名前面加两个下划线
        print('这是动物类!')

使用私有化方法

  1. 案例:验证私有方法不可被外部直接访问且不可被继承

    class Animal:
        def __showInfo(self):
            print('这是动物类!')
            pass
    
        pass
    
    
    class Bird(Animal):
        pass
    
    
    b1 = Bird()
    b1.__showInfo()
    

    运行结果:

    AI学习 Day09 面向对象基础(下)_第5张图片
  2. 案例:私有方法在类的内部可正常访问

    class Animal:
        def __showInfo(self):
            print('这是动物类!')
            pass
    
        def printData(self):
            self.__showInfo()
    
        pass
    
    
    class Bird(Animal):
        pass
    
    
    b1 = Bird()
    b1.printData()
    

    运行结果:

    AI学习 Day09 面向对象基础(下)_第6张图片
  3. 总结:

    • 私有方法不可被外部访问且不可被继承
    • 私有方法在类内部可正常访问

命名规范

  1. 头单下划线:保护类变量(不常用) _name
  2. 头双下划线:私有属性【方法】 __name
  3. 头尾双下划线:魔术方法【系统所有】,不可自定义 _init_
  4. 尾单下划线: 避免变量名与关键字冲突时可使用 class_

Property属性

获取和修改私有属性的值

方法一:调用set方法

class Animal:
    __name = '张三'

    def getName(self):
        return self.__name

    def setName(self, data):
        self.__name = data


a1 = Animal()
a1.setName('李四')  # 通过调用set方法实现私有属性值的修改
print(a1.getName())  # 调用get方法实现私有属性值的获取

运行结果:

AI学习 Day09 面向对象基础(下)_第7张图片

方法二:使用Property属性函数

Property属性函数可以通过点语法来获取、修改私有属性的值

class Animal:
    __name = '张三'

    def getName(self):
        return self.__name

    def setName(self, data):
        self.__name = data

    name = property(getName, setName)  # property()方法有两个参数,分别为get、set的方法名


a1 = Animal()
a1.name = '李四'  # 点语法实现值的修改
print(a1.name)  # 点语法实现值的获取

运行结果:

AI学习 Day09 面向对象基础(下)_第8张图片

单例模式

实现整个系统中某个类的实例只创建一次

应用场景

网站登录(例如淘宝网,只允许一个账号同时浏览)

创建单例对象

class People(object):
    __instance = None  # 私有属性用来存放首次创建的对象

    def __init__(self):
        print('对象创建成功!')

    def __new__(cls, *args, **kwargs):
        if not cls.__instance:  # 如果 __instance 为None,说明该类还未曾创建过对象
            cls.__instance = object.__new__(cls)  # 创建一个对象并用__instance记录下来
            return cls.__instance
        else:  # 如果__instance不为None代表,该类已经创建过一个对象了,只需要直接返回之前创建的那个变量【__instance】
            return cls.__instance


p1 = People()
p2 = People()
print(id(p1), id(p2))

运行结果:

AI学习 Day09 面向对象基础(下)_第9张图片

错误与异常处理

引入

age = 10
print(name)  # 未定义,运行会报错
print(age)  # 已定义,理论上可以正常显示

上面代码中,未定义name而直接输出,程序会报错如下:

AI学习 Day09 面向对象基础(下)_第10张图片

程序报错导致整个程序结束,因此age不能正常显示。

有没有办法可以输出错误内容并使程序正常运行?有,异常处理。

异常处理

  1. try…except

    age = 10
    try:
        print(name)  # 准备捕获异常的代码
    except NameError as msg:  # except后跟错误类型,as将结果重定向
        print('【{}】 异常'.format(msg))
    print(age)
    

    运行结果:

    AI学习 Day09 面向对象基础(下)_第11张图片

    拓展:如果可能有多种错误类型怎么办?

    • try跟随多个except语句

      l1 = ['hello', 1, True]
      try:
          print(l1[10])
      except NameError as msg:
          print('【{}】 异常'.format(msg))
      except IndexError as msg:
          print('【{}】 异常'.format(msg))
      

      运行结果:

      AI学习 Day09 面向对象基础(下)_第12张图片
    • 方法二:捕获所有异常(万能)

      l1 = ['hello', 1, True]
      try:
         print(l1[10])
      except Exception as msg:
         print(msg)
      

      运行结果:

      AI学习 Day09 面向对象基础(下)_第13张图片
  2. 错误栈:

    def A(data):
        return data / int(data)
    
    
    def B(data):
        return A(data) * 10
    
    
    def Func(data):
        B(data)
    
    Func(0)
    

    分析:上面出现多个函数嵌套调用,每个函数中都需要写try…except?答案是:不需要

    def A(data):
        return data / int(data)
    
    
    def B(data):
        return A(data) * 10
    
    
    def Func(data):
        try:
            B(data)
        except Exception as msg:
            print(msg)
    
    
    Func(0)
    

    运行结果:

    AI学习 Day09 面向对象基础(下)_第14张图片

    原理:

    • 如果在函数中出现错误,则会将该错误返回到上一层,直至最顶层
    • 如果错误出现在最顶层,则程序会结束

    总结:合适位置添加try…except可以极大的减少代码量

  3. else:

    当try中未出现错误,会执行else语句

    def Func(data):
        try:
            print(int(10 / int(data)))  # try里面是可以输出内容的
        except Exception as msg:
            print(msg)
        else:
            print('程序无异常!')
    
    
    Func(5)
    

    运行结果:

    AI学习 Day09 面向对象基础(下)_第15张图片
  4. finally:

    无论是否报错都会执行的语句

    def Func(data):
        try:
            print(int(10 / int(data)))  # try里面是可以输出内容的
        except Exception as msg:
            print(msg)
        finally:
            print('程序运行结束!')
    
    
    Func(5)
    

    运行结果:

    AI学习 Day09 面向对象基础(下)_第16张图片

    注意:虽然finally在这里显得很多余,但用其释放资源很方便。

自定义错误

直接或间接继承Exception类或者Error类

案例:当字符长度超过5时,抛出异常

class LenError(Exception):  # 继承Exception类
    def __str__(self):
        return '您的字符长度超过所限制的5个字符!'  # 自定义异常,msg内容来自__str__方法


str = 'hello python!'
try:
    if len(str) > 5:
        raise LenError  # raise用来抛出异常,不可用return(程序会停止运行)
    else:
        print(str)
except LenError as msg:
    print(msg)

运行结果:

AI学习 Day09 面向对象基础(下)_第17张图片

动态属性和方法

动态属性

支持实例属性和类属性的添加

  1. 添加实例属性:

    通过实例对象添加

    class Student:
        def __init__(self, name, age):
            self.name = name  # 初始方法定义实例变量
            self.age = age
    
        def __str__(self):
            return '【{}】今年【{}】岁了。'.format(self.name, self.age)
    
    
    zyh = Student('张艳华', 20)
    zyh.weight = '101'  # 动态添加实例属性
    print(zyh.weight)
    

    运行结果:

    AI学习 Day09 面向对象基础(下)_第18张图片

    动态添加的属性仅对该实例对象有效,验证:

    class Student:
        def __init__(self, name, age):
            self.name = name  # 初始方法定义实例变量
            self.age = age
    
        def __str__(self):
            return '【{}】今年【{}】岁了。'.format(self.name, self.age)
    
    
    zyh = Student('张艳华', 20)
    zyh.weight = '101'  # 动态添加实例属性
    wh = Student('王浩', 19)
    print(wh.weight)
    

    运行结果:

    AI学习 Day09 面向对象基础(下)_第19张图片
  2. 添加类属性:

    通过类对象添加

    class Student:
        def __init__(self, name, age):
            self.name = name  # 初始方法定义实例变量
            self.age = age
    
            
    zyh = Student('张艳华', 20)
    Student.weight = 101  # 动态添加类属性
    print(zyh.weight)
    

    运行结果:

    AI学习 Day09 面向对象基础(下)_第20张图片

动态方法

原理是把一个外部函数通过转换(types.MethodType())使其成为实例方法

  1. 添加实例方法:

    通过实例对象添加,仅对该实例对象有效

    import types  # 导入用来转换的types包
    
    
    class Student:
        def __init__(self, name, age):
            self.name = name  # 初始方法定义实例变量
            self.age = age
    
    
    def func(self):  # 自定义的一个外部函数,self不能忘记
        print('【{}】今年【{}】岁了!'.format(self.name, self.age))
    
    
    zyh = Student('张艳华', 20)
    zyh.printData = types.MethodType(func, zyh)  # 实例对象.方法名=types.MethodType(外部函数名, 实例对象)
    zyh.printData()  # 实例对象.方法名(调用定义的实例方法)
    

    运行结果:

    AI学习 Day09 面向对象基础(下)_第21张图片
  2. 添加类方法和静态方法:

    通过类对象实现

    class Student:
        def __init__(self, name, age):
            self.name = name  # 初始方法定义实例变量
            self.age = age
    
    
    @classmethod  # 定义的外部方法,要满足类方法的条件:1、注明@classmethod 2、第一个参数默认是cls
    def func(cls):
        print('这是一个类方法!')
    
    
    Student.testFunc = func  # 动态添加类方法(通过类对象实现的),(类对象.方法名=外部方法名)
    zyh = Student('张艳华', 20)
    zyh.testFunc()  # 验证类方法是否添加成功(实例对象调用类方法)
    

    运行结果:

    AI学习 Day09 面向对象基础(下)_第22张图片

    注意:

    • 静态方法同理(外部方法,要满足静态方法的条件)
    • 类、静态方法不需要导入types包

_slots_

限制属性

  1. 添加属性(未使用slots方法):

    class Student:
        pass
    
    
    xm = Student()
    xm.name = '小明'  # 动态添加实例属性
    xm.age = 19
    print(xm.name, xm.age)
    

    运行结果:

    AI学习 Day09 面向对象基础(下)_第23张图片
  2. 限制属性添加(使用slots方法):

    class Student:  # 使用slots方法限制属性的添加,字符串类型的属性名放入元组中,逗号分隔
        __slots__ = ('name')  # 仅允许添加一个名为name的属性
        pass
    
    
    xm = Student()
    xm.name = '小明'  # 动态添加实例属性
    xm.age = 19
    print(xm.name, xm.age)
    

    运行结果:

    AI学习 Day09 面向对象基础(下)_第24张图片

节省内存

  1. dict存放所有属性(消耗内存):

    class Student:
        pass
    
    
    xm = Student()
    xm.name = '小明'  # 动态添加实例属性
    xm.age = 19
    print(xm.__dict__)  # dict默认存放所有属性及其值
    

    运行结果:

    AI学习 Day09 面向对象基础(下)_第25张图片
  2. 使用slots后dict会被删除(节省内存):

    class Student:
        __slots__ = ('name', 'age')
        pass
    
    
    xm = Student()
    xm.name = '小明'  # 动态添加实例属性
    xm.age = 19
    print(xm.__dict__)  # dict默认存放所有属性及其值
    

    运行结果:

    AI学习 Day09 面向对象基础(下)_第26张图片

继承关系

案例1:父类限制属性(name,age),子类不限制,验证slots的限制不可继承

class Student:  # 父类
    __slots__ = ('name', 'age')  # 限制属性
    pass


class Computer(Student):  # 子类继承Student类
    pass


lm = Computer()
lm.sex = '男'  # 动态定义实例属性(该属性不在父类slots限制中)
print(lm.sex)  # 输出实例属性的内容

运行结果:

AI学习 Day09 面向对象基础(下)_第27张图片

案例2:父类限制属性(name,age),子类限制属性(sex),验证slots的限制为其并集(父类+子类)

class Student:  # 父类
    __slots__ = ('name', 'age')  # 父类限制属性
    pass


class Computer(Student):  # 子类继承Student类
    __slots__ = ('sex')  # 子类限制属性
    pass


lm = Computer()
lm.name = '李明'  # 父类限制
lm.age = 18  # 父类限制
lm.sex = '男'  # 子类限制
print('我叫【{}】,是个【{}】孩子,今年【{}】岁了!'.format(lm.name, lm.sex, lm.age))  # 输出实例属性的内容

运行结果:

AI学习 Day09 面向对象基础(下)_第28张图片

总结:

  • 若子类无slots方法,则不继承slots
  • 若子类有slots方法,slots的限制为其并集(父类+子类)

不足之处,欢迎留言,会及时回复,及时更正!

创作不易,感谢支持!

你可能感兴趣的:(人工智能,人工智能,AI,python,面向对象,笔记)