python中面向对象相关知识点(全面总结笔记)

面向对象

  • 与面向过程对比:
    • 面向过程:数学逻辑的映射,学会做个好员工
    • 面向对象:生活逻辑的映射,学会做个好领导
  • 官方定义:
    • 类:具有相同特征(属性和行为)的事物的抽象
    • 对象:某个类的具象
  • 编程语言:
    • 类:是一种自定义的数据类型
    • 对象:某个类类型的变量

面向对象语法

  • 类的定义:
    class 类名:
    内容

  • 语法说明:

    • 定义类需要使用关键字class
    • 类名:原则上只要符合标识符命名规范即可,但是通常我们都使用大驼峰(每个单词首字母大写)风格命名
      • 如:UserName
    • 类名后面的’:'不要忘记
    • 类的内容要进行整体缩进
    • 行为:通过方法体现,在类中定义相关的函数即可(第一个参数通常是self)
    • 属性:通过变量体现,在需要时动态添加,很多时候定义类时没有体现
    • 成员访问:
      • 属性:对象.属性名
      • 方法:对象.方法名()
  • 示例:
    # 定义类
    class Person:
    # 行为通过方法体现

        # 吃饭
        def eat(self):
            print('红烧鸡腿我喜欢吃')
    
        # 睡觉
        def sleep(self):
            print('睡觉也是一种生活态度')
            
    # 定义对象
    liang = Person()
    # 调用方法
    liang.eat()
    liang.sleep()
    # 属性时动态添加的
    liang.name = '某某某'
    # 获取属性
    print(liang.name)
    
  • self使用
    class Person:
    def run(self):
    # self表示当前对象:谁调用该方法就表示谁
    print(’{}每天以2m/s的速度慢跑5km’.format(self.name))

        def introduce(self):
            # 不但可以访问成员属性
            print('我叫{}'.format(self.name))
            # 还可以调用成员方法
            self.run()
            
    fei = Person()
    fei.name = '路人甲'
    fei.run()
    fei.introduce()
    
    long = Person()
    long.name = '路人乙'
    long.introduce() 
    
    • 说明:
      1.类中的每个成员方法都有一个self参数,调用的时候不需要传递该参数
      2.该参数的名字可以不是self,只不过通常我们都使用这个
      3.self表示当前对象,对调用该方法self就代表谁,哪个对象调用就表示哪个对象
      4.通过self可以访问成员属性,也可以调用成员方法
  • __str__方法
    class Person:
    # 使用print方法打印对象,默认打印 类名 + 地址
    # 若想打印特定内容,重写该方法即可,要求返回一个字符串
    def str(self):
    return ‘我叫{},今年{}’.format(self.name, self.age)

    james = Person()
    james.name = '路人丙'
    james.age = 33
    print(james)    
    
  • 构造方法:创建对象后,初始化属性时,系统会自动调用该方法
    class Cat:
    def str(self):
    return ‘name:{},age:{},color:{}’.format(self.name, self.age, self.color)

        # 构造方法:创建对象后,初始化系统就会自动调用该方法
        def __init__(self, name, age, color):
            print('__init__')
            self.name = name
            self.age = age
            self.color = color
            
    # 这种形式比较繁琐
    # tom = Cat()
    # tom.name = 'Tom'
    # tom.age = 3
    # tom.color = '蓝色'
    
    # 这种比较简洁
    tom = Cat('Tom', 3, '蓝色')
    print(tom) 
    
  • 析构方法:当对象释放时系统会自动调用,通常用于释放资源
    class Pig:
    # 析构方法:当对象释放时,系统会自动调用
    # 若手动使用del删除,则会立即调用该方法
    # 该方法一般做资源释放处理:数据库连接断开,文件关闭
    def del(self):
    print(‘大师兄,我不行了’)

    bajie = Pig()
    del bajie
    print('八戒,一路走好!')        
    
  • 示例:小明手里有两张牌,左右♥K,右手♠A,小明交换两手的牌后,手里分别是什么?

    • 思路:

      • 先找到对象:左手、右手、♥K、♠A、小明
      • 根据对象抽象出对应的类:人、手、牌
      • 根据需要写出相应的逻辑,很可能反过来完善类的设计
      • 按照题目要求创建相关对象,调用相关方法,实现相关功能
    • 代码:

      对象:小明、左手、右手、♥K、♠A

      类:人、手、牌

      设计相应的类

      扑克牌

      class Poker:
      def init(self, color, number):
      self.color = color
      self.number = number

        def __str__(self):
        	return '{}{}'.format(self.color, self.number) 
      

      创建两张牌

      p1 = Poker(‘♥’, ‘K’)
      p2 = Poker(‘♠’, ‘A’)

      手的类

      class Hand:
      def init(self, poker):
      self.poker = poker

        def hold_poker(self, poker):
            self.poker = poker
      

      创建左右两只手

      left_hand = Hand(p1)
      right_hand = Hand(p2)

      人的类

      class Person:
      def init(self, name, left_hand, right_hand):
      self.name = name
      self.left_hand = left_hand
      self.right_hand = right_hand

      # 展示手里的牌
      def show(self):
      	print('{}张开手'.format(self.name), end=' ')
            print('左手:{}'.format(self.left_hand.poker), end=',')
            print('右手:{}'.format(self.right_hand.poker))
      
      # 交换两手的牌
        def swap(self):
            self.left_hand.poker, self.right_hand.poker = self.right_hand.poker, self.left_hand.poker
            print('{}交换两手的牌'.format(self.name))   
      

      创建小明对象

      xiaoming = Person(‘小明’, left_hand, right_hand)

      展示手里的牌

      xiaoming.show()

      交换两手的牌

      xiaoming.swap()

      #再次展示
      xiaoming.show()

常用内置函数

  • 内置函数:在类的内部,特定时机自动触发的函数。

  • 示例:setattr、getattr、delattr
    class Person:
    def init(self, name):
    self.name = name

          def __str__(self):
              return '姓名:{}'.format(self.name)
    
          def __del__(self):
              print('对象即将销毁')
              
          # 当获取不存在的属性时,会自动触发该方法
          def __getattr__(self, item):
              if item == 'age':
                  return 18
              else:
                  return '你猜'
    
          # 当设置不存在的属性时,会自动触发该方法
          def __setattr__(self, key, value):
              print(key, value)
              self.__dict__[key] = value
    
          # 销毁对象成员属性时,会自动触发该方法
          def __delattr__(self, item):
              print(item, '即将销毁')
            
    xiaoming = Person('小明')
    xiaoming.age = 20
    print(xiaoming.age)
    # 存放对象的所有属性
    # print(xiaoming.__dict__)
    # print(xiaoming)
    del xiaoming.age         
    
  • 将对象当做字典操作,特定时机会自动触发的方法
    class Person:
    # 将对象当做字典操作,设置键值对时会触发该方法
    def setitem(self, key, value):
    # print(key, value)
    self.dict[key] = value

        # 将对象当做字典操作,根据键获取值时会触发该方法
        def __getitem__(self, item):
            # print(item)
            return self.__dict__.get(item)
    
        # 将对象当做字典操作,删除指定的键值对时自动触发
        def __delitem__(self, key):
            del self.__dict__[key]
            
    xiaoming = Person()
    
    xiaoming['name'] = '小明'
    print(xiaoming.dict)
    
    print(xiaoming['name'])
    
    del xiaoming['name']         
    
  • 将对象当做函数调用时,会自动触发下面方法
    class Person:
    # 将对象当做函数调用时,会自动触发该方法
    def call(self, *args, **kwargs):
    # print(‘call’)
    return sum(args)

    xiaoming = Person()
    
    # 这样操作,需要提供call方法
    ret = xiaoming(1, 2, 3, name='小明')
    print(ret)   
    
  • 函数判断
    class A:
    def call(self, *args, **kwargs):
    pass

    def test():
        pass
    
    a = A()
    
    # 判断是否可调用
    print(callable(test))
    print(callable(a))
    
    # 判断是否拥有'__call__'属性
    print(hasattr(test, '__call__'))
    print(hasattr(a, '__call__'))
    
    # 判断是否是函数
    from inspect import isfunction
    print(isfunction(test))
    print(isfunction(a))
    

面向对象三大特点

  • 封装:既可对数据结构进行封装,又可对处理数据的方法进行封装
  • 继承:强调的父子类的关系
  • 多态:不同对象调用相同的方法,会有不同的响应

类的继承

  • 相关概念

    • 继承:父类的属性和方法,子类直接拥有,称为继承
    • 派生:子类在父类的基础上衍生出新的特征(属性和行为)
    • 总结:其实他们是一回事,只是描述问题的侧重点不同(继承强调相同点,派生强调不同点)
  • 继承语法
    # class Animal(object):
    # 当没有指定父类时,默认继承object
    class Animal:
    def init(self, name):
    self.name = name

        def eat(self):
            print('小动物喜欢一天到晚吃个不停')
    
    # 继承自Animal
    class Dog(Animal):
        pass
    
    d = Dog('旺财')
    # 可以拥有父类的方法
    d.eat()
    # 也可以拥有父类的属性
    print(d.name)
    
  • 派生示例
    class Animal:
    def run(self):
    print(‘小动物喜欢成天跑个不停’)

    class Cat(Animal):
        def eat(self):
            print('猫喜欢吃老鼠')
    
    tom = Cat()
    
    tom.run()
    # 多出来的行为
    tom.eat()
    
    # 多出来的属性
    tom.color = '蓝色'
    print(tom.color)
    
  • 重写方法

    • 若父类的方法完全不合适,可以进行覆盖重写

    • 若父类的方法不够完善,可以添枝加叶进行完善

    • 示例:
      class Animal:
      def eat(self):
      print(‘小动物一天到晚的出个不停’)

        def run(self):
            print('小动物一天到晚的四处连跑')
      

      class Cat(Animal):
      # 父类的方法完全不合适,覆盖重写
      def run(self):
      print(‘俺走的时猫步’)

        # 父类的方法部分合适,需要添加内容进行完善
        def eat(self):
            # 保留父类的内容,不建议使用此方式
            # Animal.eat(self)
            # super(Cat, self).eat()
            # 类名及self可以不传
            super().eat()
            print('不过俺喜欢吃鱼')
      

      jiafei = Cat()
      jiafei.run()
      jiafei.eat()

  • 多继承:一个子类可以拥有多个父类
    class A:
    def eat(self):
    print(‘eat func in class A’)

    class B:
        def eat(self):
            print('eat func in class B')
    
    class C(A, B):
        def eat(self):
            # 这种方案是默认的继承顺序进行选择的父类方法
            # super().eat()
            # 人为指定调用某个父类的方法
            B.eat(self)
    
    c = C()
    c.eat()
    

访问权限

  • 权限

    • 公有的:类中的普通的属性和方法,默认都是公有的;可以在类内、类外、子类中使用
    • 私有的:定义时在前面添加两个’_’,就变成了私有的;只能在类内使用,不能在类外及子类中使用
  • 示例:
    class Person:
    def init(self, name):
    self.name = name
    self.__age = 20

        def eat(self):
            print('民以食为天')
    
        def __test(self):
            print('__test')
    xiaoming = Person('小明')
    print(xiaoming.name)
    xiaoming.eat()
    #不能在类外使用
    #print(xiaoming.__age)
    xiaoming._Person__test()
    print(xiaoming.dict)
    #尽管可以这样访问私有属性,但是强烈建议不要这样使用
    #print(xiaoming._Person__age)
    class Man(Person):
     def introduce(self):
          # 不能在子类中使用
          # print(self.__age)
          print('我叫{}'.format(self.name))
          self.eat()
    m = Man('亮亮')
    m.introduce()
    

类属性

  • 说明:定义类时,写在方法外的属性,通常会写在类的开头,这样的属性称为类属性

  • 示例:
    class Person:
    # 类属性,通过类名访问,属于整个类,而不是某个对象
    # nation = ‘中国’

        # 限制可以使用的属性,提高访问的效率
        # 也可以提高访问速度,减少内存使用
        __slots__ = ('name', 'age', 'nation')
    
        def __init__(self, name):
            self.name = name
            self.nation = 'china'
    p1 = Person('小明')
    p2 = Person('小红')
    print(p1.name, p2.name)
    print(Person.nation)
    #p1.nation = 'china'
    print(p1.nation)
    print(p2.nation)
    #print(Person.nation)
    p1.age = 20
    #p1.height = 180
    
    #特殊的类属性
    #表示类名的字符串
    
      print(Person.name)
    
    #表示父类构成的元组
    
      print(Person.bases)
    
    #存储类的相关信息
    
      print(Person.dict)
    
    #限制可以使用的属性
    
      print(Person.slots)
    

类方法

  • 说明:

    • 定义时使用classmethod装饰器装饰的方法
    • 使用时通过类名调用
  • 作用:

    • 可以创建对象或者简洁的创建对象
    • 对外提供简单易用的接口
  • 示例1:创建对象

    class Person:
        def eat(self):
            print('我喜欢吃麻辣烫,不要麻椒和辣椒')
    
        @classmethod
        def test(cls):
            print(cls)
            print('类方法')
    
        # 创建对象,或者简洁的创建对象
        @classmethod
        def create(cls):
            p = cls()
            p.age = 1
            return p
    
    p1 = Person()
    p1.eat()
    
    # 通过类名调用
    Person.test()
    # 创建或简洁的创建对象
    p2 = Person.create()
    print(type(p2))
    
  • 示例2:提供接口
    class Number:
    def init(self, num1, num2):
    self.num1 = num1
    self.num2 = num2

        def add(self):
            return self.num1 + self.num2
    
        def sub(self):
            return self.num1 - self.num2
    
        def mul(self):
            return self.num1 * self.num2
    
        def div(self):
            if self.num2 == 0:
                return None
            return self.num1 / self.num2
    
        # 对外提供简单易用的接口
        @classmethod
        def pingfanghe(cls, num1, num2):
            n1 = cls(num1, num1)
            n12 = n1.mul()
    
            n2 = cls(num2, num2)
            n22 = n2.mul()
    
            n3 = cls(n12, n22)
            return n3.add()
    he = Number.pingfanghe(3, 4)
    print(he)
    

静态方法

  • 说明:

    • 使用staticmethod装饰器装饰的方法(方法没有cls参数)
    • 通过类名进行调用
  • 示例:
    class Person:
    @staticmethod
    def test():
    print(‘static method test’)

        # 创建对象
        @staticmethod
        def create():
            p = Person()
            return p
    #Person.test()
    #p = Person.create()
    #print(p)
    

    、 class Animal:
    def run(self):
    pass
    class Dog(Animal):
    def run(self):
    print(‘狗通常走S型’)
    class Cat(Animal):
    def run(self):
    print(‘猫平时走猫步,偶尔突然加速’)
    def test(obj):
    obj.run()
    d = Dog()
    c = Cat()
    test(d)
    test©

属性函数

  • 说明:将成员方法当做属性一样进行访问

  • 作用:保护特定属性,或者对特定属性进行处理

  • 示例:

    class User:
        def __init__(self, username, password):
            self.username = username
            self.__password = password
    
        # 该方法可以像成员属性一样访问
        @property
        def password(self):
            print('有人想查看密码')
            return '想偷看密码,没门'
            # return self.__password
    
        # 在设置密码时,会自动调用
        @password.setter
        def password(self, password):
            print('@password.setter', password)
            self.__password = '加密' + password + '加密'
    
    
    u = User('xiaoming', '111111')
    # print(u.password())
    print(u.password)
    
    # 设置密码,会自动调用setter方法
    u.password = 'abcde'
    

面向对象及异常处理

内置函数

  • 总结:initdelstr、attr系列、item系列、call

  • str__与__repr

    • 使用print/str方法时会自动触发__str__方法,当__str__不存在,尝试__repr__
    • 使用repr方法时会自动触发__repr__方法
    • repr方法通常用于返回对象的字符串表示形式
    • 这两个方法都只能返回字符串
    • eval方法可以将一个字符串当做有效的代码执行
  • 算术运算符重载

    • 示例:
      class Number:
      def init(self, num):
      self.num = num

        # 对象出现在'+'左边时会自动触发
        def __add__(self, other):
            print('__add__')
            return self.num + other
      
        # 对象出现在'+'右边是会自动触发
        def __radd__(self, other):
            print('__radd__')
            return self.num + other
      
        # +=运算时会自动触发,没有时会触发 __add__
        def __iadd__(self, other):
            print('__iadd__')
            return Number(self.num + other)
      

      n = Number(100)
      ret = n + 200
      ret = 200 + n
      print(ret)
      n += 200 # n = n + 200
      print(n)

    • 自己测试
      加法:addraddiadd
      减法:subrsubisub
      乘法:mulrmulimul
      除法:truedivrtruedivitruediv
      求余:__mod、rmodimod

  • 关系运算符重载
    >: gt
    =: ge
    <: lt
    <=: le
    ==: eq
    !=: ne

  • 示例
    class Number:
    def init(self, num):
    self.num = num

          def __gt__(self, other):
              print('__gt__')
              return self.num > 200
    
          def __lt__(self, other):
              print('__lt__')
              return self.num < other
    
          def __eq__(self, other):
              print('__eq__')
              return self.num == other
    
          # 当没有此方法时,使用!=也会触发__eq__方法
          def __ne__(self, other):
              print('__ne__')
              return self.num != other
        
    n = Number(100)
    
    # print(n > 200)
    # print(200 > n)
    # print(200 == n)
    print(200 != n)     
    

深浅拷贝

  • 引用计数

    • python中的所有变量都是对象,对象的管理采用的时引用计数的方式
    • 当多一个变量指向对象计数值加1,当少一个变指向对象计数值减1,减到0是,释放对象(del)
  • 函数传参

    • 对于不可变的变量来说,函数中不可能改传递过来的变量
    • 对于可变的容器对象及自定义对象,作为函数参数传递时,传递的是引用,可以修改该对象
  • 深浅拷贝
    class Person:
    def del(self):
    print(‘对象释放’)

    p1 = Person()
    p2 = p1
    
    print(id(p1))
    print(id(p2))
    
    del p1
    del p2
    print('OVER')
    
    def test(m):
    	# m += 1
    	m[0] = 300
    
    # n = 100
    n = [100, 200]
    
    test(n)
    print(n)
    
    import copy
    
    lt = [1, 2, [3, 4]]
    
    # 浅拷贝,只拷贝对象本身,不拷贝对象中的元素
    # lt2 = lt.copy()
    # 浅拷贝
    lt2 = copy.copy(lt)
    
    # 深拷贝:不但拷贝对象本身,还拷贝对象中的元素
    lt2 = copy.deepcopy(lt)
    lt[0] = 100
    lt2 = 300
    
    print(id(lt))
    print(id(lt2))
    print(lt)
    print(lt2)
    

数据持久化(pickle)

  • 说明:数据持久化存储方案,普通文件、序列化、数据库

  • 示例:
    import pickle

    class Person:
        def __init__(self, name, age):
            self.name = name
            self.age  = age
    
        def __str__(self):
            return 'name:{},age:{}'.format(self.name, self.age)
        
    xiaoming = Person('xiaoming', 20)
    # 转换为bytes类型
    
    # s = pickle.dumps(xiaoming)
    # print(s)
    
    # 从字节流中提取对象
    # xm = pickle.loads(s)
    
    # print(xm)
    # 保存到文件中
    # fp = open('data.txt', 'wb')
    
    # pickle.dump(xiaoming, fp)
    # 从文件中获取对象
    
    fp = open('data.txt', 'rb')
    xm = pickle.load(fp)
    print(xm)
    

异常处理

  • 相关概念

    • 错误:程序运行之前的语法问题,如:关键字、缩进、括号不成对等
    • 异常:在程序运行过程中出现的问题,如:未定义变量、除数为0、属性不存在等
  • 异常处理

    • 说明:异常处理可以理解为特殊的流程控制语句,可以提高代码的健壮性。
  • 异常语法:
    try:
    print(‘正常代码’)
    # print(a)
    3/0
    except Exception as e:
    # Exception 是所有异常的基类,此处可以捕获所有的异常
    print(‘出现异常’)
    print(e)

      print('其他内容')
    
  • 多个异常
    # 分类捕获异常
    ‘’’
    try:
    # print(a)
    # 3/0
    d = {}
    print(d[‘name’])
    except NameError as e:
    print(‘NameError:’, e)
    except ZeroDivisionError as e:
    print(‘ZeroDivisionError:’, e)
    except Exception as e:
    print(‘OtherError:’, e)
    ‘’’

    try:
        # print(a)
        # 3/0
        fp = open('123.txt')
    except (NameError, ZeroDivisionError) as e:
        # 将某些异常进行统一处理,写在一个元组中即可
        print(e)
    except:
        print('其他异常')
    
  • 完整结构(else-finally)
    try:
    print(‘正常代码’)
    print(a)
    except:
    # 出现异常时执行
    print(‘出现异常’)
    else:
    # 正常结束(没有异常)时会执行
    print(‘正常结束’)
    finally:
    # 无论有无异常,都会执行
    print(‘最后执行’)
    else:正常结束时执行else中的代码
    finally:无论有无异常,最后都执行

  • 抛出异常:raise
    try:
    print(‘正常代码’)
    # 根据业务逻辑的需要,手动抛出异常
    raise Exception(‘手动抛出的异常’)
    except Exception as e:
    print(‘异常:’, e)

    print('OVER')
    
  • 异常嵌套(try-except结构中再次使用try-except结构)
    print(‘我要去上班,什么事也阻止不了我上班的脚步’)
    try:
    print(‘我准备骑电动车’)
    raise Exception(‘昨天晚上不知道哪个缺德的家伙把我充电器拔了’)
    print(‘骑车提前到达公司’)
    except Exception as e:
    print(e)
    try:
    print(‘我准备做公交车’)
    raise Exception(‘等了20分钟一直没有公交车,果断放弃’)
    print(‘坐公交车准时到达公司’)
    except Exception as e:
    print(e)
    print(‘我准备打车’)
    print(‘打车还是快,一会就到达公司’)

    print('热情满满的开始一天的工作')
    
  • 自定义异常类(需要继承自官方的异常基类Exception)
    # 自定义异常类
    class MyException(Exception):
    def init(self, msg):
    self.msg = msg

        def __str__(self):
            return self.msg
    
        # 特定异常标准处理方案
        def deal(self):
            print('处理特定的自定义异常')
            
    try:
        print('正常执行')
      	# 手动抛出自定义异常
      	raise MyException('出现了自定义异常')
    except MyException as e:
        print(e)
      	# 调用方法,处理异常
      	e.deal()
    
  • 特殊场景

    • 当我们进行文件操作时,无论过程中是否有异常,最终我们一定得进行关闭操作
    • 使用with语句,可以保证文件的关闭,无论中间过程是否出现异常

      fp = open(‘test.txt’, ‘r’)

      # 中间无论有无异常,最后一定得关闭文件
      # fp.close()
      
      with open('test.txt', 'r') as fp:
          content = fp.read(5)
          print(content)
          # 此处不要考虑文件的关闭问题,也不用是否有异常
      

你可能感兴趣的:(python基础)